I have a LCD that I use to display timecode of the movie I am watching on my XBMC, and I would like to display current date and hour when nothing is played. The machine hosting the LCD is running a python TCPSocketServer server receiving text to be displayed from my XBMC installation. The problem is that I have to keep an active network connection so XBMC can send the hour and date through the socket and the LCD can display it. In my opinion, the best thing to do would be to display the date of the machine hosting the LCD and then switch to a "timecode view" when the socket is active.
Is there any "pythonic" way set up a TCPSocketServer that compute a loop for displaying the date while waiting for a connection, and then change its behaviour to compute data received through the socket ?
Many thanks in advance
Here's some code that does what you want. It starts up a TCP server listening to text sent to port 9876. When it gets some text it sends it to the Display object. The code also sets up a timer which runs once a second, sending "idle text" (ie: the current timestamp) to the display object.
The display gets normal update text (from the server), and "idle text" from the 2nd thread. The object knows how long it's been since it got some real text, and displays one or the other messages.
If the display object was attached to hardware, it could use a multiprocessing.RLock
or other mechanism to protect itself.
Have fun!
import signal, SocketServer, threading, time
class Display(object):
IDLE_TIME = 5 # seconds
def __init__(self):
self.updated = None
self.write('Hello')
def _write(self, arg):
print 'DISPLAY:', arg
def write(self, arg):
"""
update display and 'last updated' timestamp
"""
self._write(arg)
self.updated = time.time()
def idle(self, arg):
"""
update display only if it's been a few seconds
"""
if time.time() - self.updated >= self.IDLE_TIME:
self._write(arg)
class DisplayHandler(SocketServer.BaseRequestHandler):
DisplayObj = None # class var
def handle(self):
text = self.request.recv(1024).strip()
print "{} wrote: {}".format(
self.client_address[0], text,
)
# send text to LCD immediately
self.DisplayObj.write(text)
def check_idle(display_obj):
"""
update display with current time if it's idle
"""
while True:
display_obj.idle(
time.strftime('time: %H:%M:%S'),
)
time.sleep(1)
def start_server(host, port):
"""
start (single threaded) server
"""
SocketServer.TCPServer(
(host, port),
DisplayHandler,
).serve_forever()
def main(host, port):
display = Display()
# store global display obj so Handler can get to it
DisplayHandler.DisplayObj = display
print 'serving on {}:{}'.format(host, port)
print 'Example: echo beer | nc localhost {}'.format(port)
print
server_t = threading.Thread(
target=start_server, args=(host, port)
)
server_t.daemon = True
server_t.start()
idle_t = threading.Thread(
target=check_idle, args=[display],
)
idle_t.daemon = True
idle_t.start()
# wait for control-C to interrupt
try:
signal.pause()
except KeyboardInterrupt:
pass
if __name__ == "__main__":
main("localhost", 9876)
Here I started the server, waited a few seconds, then typed fortune -s | nc localhost 9876
to send a short fortune cookie to my LCD server.
Notice the "idle timer" stopped at :07
, output the fortune cookie, waited five seconds, then continued with :13
, :14
. The message displayed for five seconds before switching back to the idle timestamp.
python ./lcdcontrol.py
DISPLAY: Hello
serving on localhost:9876
Example: echo beer | nc localhost 9876
DISPLAY: time: 13:08:06
DISPLAY: time: 13:08:07
127.0.0.1 wrote: Some people need a good imaginary cure for their painful imaginary ailment.
DISPLAY: Some people need a good imaginary cure for their painful imaginary ailment.
DISPLAY: time: 13:08:13
DISPLAY: time: 13:08:14
DISPLAY: time: 13:08:15
DISPLAY: time: 13:08:16