Skip to content

Instantly share code, notes, and snippets.

@evindunn
Last active September 28, 2021 21:33
Show Gist options
  • Save evindunn/1734d841e183dfb250ca4a367ca089db to your computer and use it in GitHub Desktop.
Save evindunn/1734d841e183dfb250ca4a367ca089db to your computer and use it in GitHub Desktop.
Raspberry Pi i2C LCD Server
#!/usr/bin/env python3
from RPLCD.i2c import CharLCD
from argparse import ArgumentParser
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
from json import dumps as json_dumps
from sys import stderr
from threading import Lock
from board import I2C
I2C_ADDR_DEFAULT = "0x27"
I2C_TYPE_DEFAULT = "PCF8574"
I2C_ROWS = 2
I2C_COLS = 16
class Handler(BaseHTTPRequestHandler):
CODE_BAD_REQUEST = 400
CODE_NO_CONTENT = 204
CODE_INTERNAL_SERVER_ERROR = 500
protocol_version = "HTTP/1.1"
error_content_type = "application/json;charset=utf-8"
error_message_format = json_dumps({"message": "%(explain)s"})
@property
def content_length(self):
if self.headers["Content-Length"] is None:
return None
return int(self.headers["Content-Length"])
def do_POST(self):
try:
if not self.content_length:
self.send_error(Handler.CODE_BAD_REQUEST, explain="Content-Length is not set")
elif not "Content-Type" in self.headers.keys() or not self.headers["Content-Type"].startswith("text/plain"):
self.send_error(Handler.CODE_BAD_REQUEST, explain="Plaintext should be sent")
else:
with self.server.lcd_lock:
#self.server.lcd.clear()
self.server.lcd.cursor_pos = (0, 0)
self.server.lcd.write_string(self.rfile.read(self.content_length).decode("utf-8"))
self.send_response(Handler.CODE_NO_CONTENT)
except Exception as e:
self.log_error(str(e))
self.send_response(Handler.CODE_INTERNAL_SERVER_ERROR)
self.end_headers()
class Server(ThreadingHTTPServer):
allow_reuse_address = True
def __init__(self, address, handler, lcd_i2c, lcd_address, lcd_rows, lcd_cols):
super().__init__(address, handler)
self.lcd = CharLCD(lcd_i2c, lcd_address, rows=lcd_rows, cols=lcd_cols)
self.lcd_lock = Lock()
self.lcd.clear()
if __name__ == "__main__":
parser = ArgumentParser(description="LCD Server")
parser.add_argument("port", type=int, help="The port to the the server on")
parser.add_argument("--lcd-address", type=str, help="The i2c address of the LCD", default=I2C_ADDR_DEFAULT)
parser.add_argument("--lcd-i2c", choices=("PCF8574", "MCP23008", "MCP23017"), help="The i2c backpack type for the LCD", default=I2C_TYPE_DEFAULT)
parser.add_argument("--lcd-rows", type=int, help="The number of rows on the LCD", default=I2C_ROWS)
parser.add_argument("--lcd-cols", type=int, help="The number of columns on the LCD", default=I2C_COLS)
args = parser.parse_args()
try:
lcd_address = int(args.lcd_address, 16)
except:
print("Invalid LCD address, this should be a hexidecimal number (e.g. '0x27')", file=stderr)
exit(1)
with Server(("0.0.0.0", args.port), Handler, args.lcd_i2c, lcd_address, args.lcd_rows, args.lcd_cols) as httpd:
print("Server running on port {}...".format(args.port))
try:
httpd.serve_forever()
except KeyboardInterrupt:
httpd.shutdown()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment