annotate light_bridge.py @ 27:32cfefe3155b

try harder to crash if there's an mqtt error, so k8s does a full restart
author drewp@bigasterisk.com
date Sat, 23 Mar 2024 15:25:02 -0700
parents cee43f550577
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
drewp@bigasterisk.com
parents:
diff changeset
1 """
drewp@bigasterisk.com
parents:
diff changeset
2 replaces a lot of mqtt_to_rdf and rdf_to_mqtt
drewp@bigasterisk.com
parents:
diff changeset
3 """
11
028ed39aa78f more ts types; attempted multiplayer but the change events are managed wrong
drewp@bigasterisk.com
parents: 10
diff changeset
4 import asyncio
0
drewp@bigasterisk.com
parents:
diff changeset
5 import json
drewp@bigasterisk.com
parents:
diff changeset
6 import logging
27
32cfefe3155b try harder to crash if there's an mqtt error, so k8s does a full restart
drewp@bigasterisk.com
parents: 25
diff changeset
7 import os
7
05fb0319eb64 cleanup
drewp@bigasterisk.com
parents: 6
diff changeset
8 import time
2
c6fd04e07db0 refactor light.py
drewp@bigasterisk.com
parents: 1
diff changeset
9 from functools import partial
0
drewp@bigasterisk.com
parents:
diff changeset
10
27
32cfefe3155b try harder to crash if there's an mqtt error, so k8s does a full restart
drewp@bigasterisk.com
parents: 25
diff changeset
11 import uvicorn
0
drewp@bigasterisk.com
parents:
diff changeset
12 from patchablegraph import PatchableGraph
drewp@bigasterisk.com
parents:
diff changeset
13 from patchablegraph.handler import GraphEvents, StaticGraph
2
c6fd04e07db0 refactor light.py
drewp@bigasterisk.com
parents: 1
diff changeset
14 from sse_starlette.sse import EventSourceResponse
0
drewp@bigasterisk.com
parents:
diff changeset
15 from starlette.applications import Starlette
drewp@bigasterisk.com
parents:
diff changeset
16 from starlette.requests import Request
drewp@bigasterisk.com
parents:
diff changeset
17 from starlette.responses import JSONResponse
drewp@bigasterisk.com
parents:
diff changeset
18 from starlette.routing import Route
drewp@bigasterisk.com
parents:
diff changeset
19 from starlette_exporter import PrometheusMiddleware, handle_metrics
2
c6fd04e07db0 refactor light.py
drewp@bigasterisk.com
parents: 1
diff changeset
20
27
32cfefe3155b try harder to crash if there's an mqtt error, so k8s does a full restart
drewp@bigasterisk.com
parents: 25
diff changeset
21 from color import Color
7
05fb0319eb64 cleanup
drewp@bigasterisk.com
parents: 6
diff changeset
22 from light import Lights
14
e3dbd04dab96 add mqtt; talk to first light (no throttling)
drewp@bigasterisk.com
parents: 11
diff changeset
23 from mqtt_io import MqttIo
27
32cfefe3155b try harder to crash if there's an mqtt error, so k8s does a full restart
drewp@bigasterisk.com
parents: 25
diff changeset
24
0
drewp@bigasterisk.com
parents:
diff changeset
25 logging.basicConfig(level=logging.INFO)
drewp@bigasterisk.com
parents:
diff changeset
26 log = logging.getLogger()
drewp@bigasterisk.com
parents:
diff changeset
27
drewp@bigasterisk.com
parents:
diff changeset
28
drewp@bigasterisk.com
parents:
diff changeset
29 async def output(lights: Lights, request: Request) -> JSONResponse:
drewp@bigasterisk.com
parents:
diff changeset
30 light = lights.byName(request.query_params['light'])
10
140633abfa2a route colors from PUT to Light.setColor
drewp@bigasterisk.com
parents: 7
diff changeset
31 body = (await request.body()).decode('utf8')
140633abfa2a route colors from PUT to Light.setColor
drewp@bigasterisk.com
parents: 7
diff changeset
32 await light.setColor(Color.fromHex(body))
5
7eeda7f4f9cd spell it to_dict, for compat with DataClassJsonMixin
drewp@bigasterisk.com
parents: 2
diff changeset
33 return JSONResponse(light.to_dict())
0
drewp@bigasterisk.com
parents:
diff changeset
34
27
32cfefe3155b try harder to crash if there's an mqtt error, so k8s does a full restart
drewp@bigasterisk.com
parents: 25
diff changeset
35
25
cee43f550577 add /lightNames
drewp@bigasterisk.com
parents: 14
diff changeset
36 async def lightNames(lights: Lights, request: Request) -> JSONResponse:
cee43f550577 add /lightNames
drewp@bigasterisk.com
parents: 14
diff changeset
37 return JSONResponse({'lightNames': lights.allNames()})
cee43f550577 add /lightNames
drewp@bigasterisk.com
parents: 14
diff changeset
38
0
drewp@bigasterisk.com
parents:
diff changeset
39
drewp@bigasterisk.com
parents:
diff changeset
40 async def table(lights: Lights, req: Request) -> EventSourceResponse:
drewp@bigasterisk.com
parents:
diff changeset
41
11
028ed39aa78f more ts types; attempted multiplayer but the change events are managed wrong
drewp@bigasterisk.com
parents: 10
diff changeset
42 def updateMessage():
028ed39aa78f more ts types; attempted multiplayer but the change events are managed wrong
drewp@bigasterisk.com
parents: 10
diff changeset
43 return json.dumps({'now': time.time()} | lights.to_dict())
028ed39aa78f more ts types; attempted multiplayer but the change events are managed wrong
drewp@bigasterisk.com
parents: 10
diff changeset
44
0
drewp@bigasterisk.com
parents:
diff changeset
45 async def g():
11
028ed39aa78f more ts types; attempted multiplayer but the change events are managed wrong
drewp@bigasterisk.com
parents: 10
diff changeset
46 yield updateMessage()
028ed39aa78f more ts types; attempted multiplayer but the change events are managed wrong
drewp@bigasterisk.com
parents: 10
diff changeset
47 async for ping in lights.changes(): # broken if there's more than one caller!
028ed39aa78f more ts types; attempted multiplayer but the change events are managed wrong
drewp@bigasterisk.com
parents: 10
diff changeset
48 log.info('send table event')
028ed39aa78f more ts types; attempted multiplayer but the change events are managed wrong
drewp@bigasterisk.com
parents: 10
diff changeset
49 yield updateMessage()
028ed39aa78f more ts types; attempted multiplayer but the change events are managed wrong
drewp@bigasterisk.com
parents: 10
diff changeset
50 await asyncio.sleep(.5) # slow down the inf loop
0
drewp@bigasterisk.com
parents:
diff changeset
51
drewp@bigasterisk.com
parents:
diff changeset
52 return EventSourceResponse(g())
drewp@bigasterisk.com
parents:
diff changeset
53
drewp@bigasterisk.com
parents:
diff changeset
54
27
32cfefe3155b try harder to crash if there's an mqtt error, so k8s does a full restart
drewp@bigasterisk.com
parents: 25
diff changeset
55 def crash(request: Request):
32cfefe3155b try harder to crash if there's an mqtt error, so k8s does a full restart
drewp@bigasterisk.com
parents: 25
diff changeset
56 log.info('crash requested')
32cfefe3155b try harder to crash if there's an mqtt error, so k8s does a full restart
drewp@bigasterisk.com
parents: 25
diff changeset
57 os.abort()
32cfefe3155b try harder to crash if there's an mqtt error, so k8s does a full restart
drewp@bigasterisk.com
parents: 25
diff changeset
58
32cfefe3155b try harder to crash if there's an mqtt error, so k8s does a full restart
drewp@bigasterisk.com
parents: 25
diff changeset
59
0
drewp@bigasterisk.com
parents:
diff changeset
60 def main():
14
e3dbd04dab96 add mqtt; talk to first light (no throttling)
drewp@bigasterisk.com
parents: 11
diff changeset
61 mqtt = MqttIo()
e3dbd04dab96 add mqtt; talk to first light (no throttling)
drewp@bigasterisk.com
parents: 11
diff changeset
62 lights = Lights(mqtt)
0
drewp@bigasterisk.com
parents:
diff changeset
63 graph = PatchableGraph()
drewp@bigasterisk.com
parents:
diff changeset
64 app = Starlette(debug=True,
drewp@bigasterisk.com
parents:
diff changeset
65 routes=[
drewp@bigasterisk.com
parents:
diff changeset
66 Route('/api/output', partial(output, lights), methods=['PUT']),
25
cee43f550577 add /lightNames
drewp@bigasterisk.com
parents: 14
diff changeset
67 Route('/api/lightNames', partial(lightNames, lights), methods=['GET']),
0
drewp@bigasterisk.com
parents:
diff changeset
68 Route('/api/table', partial(table, lights)),
drewp@bigasterisk.com
parents:
diff changeset
69 Route('/api/graph', StaticGraph(graph)),
drewp@bigasterisk.com
parents:
diff changeset
70 Route('/api/graph/events', GraphEvents(graph)),
27
32cfefe3155b try harder to crash if there's an mqtt error, so k8s does a full restart
drewp@bigasterisk.com
parents: 25
diff changeset
71 Route('/api/crash', crash),
0
drewp@bigasterisk.com
parents:
diff changeset
72 ])
drewp@bigasterisk.com
parents:
diff changeset
73
drewp@bigasterisk.com
parents:
diff changeset
74 app.add_middleware(PrometheusMiddleware, app_name='light-bridge')
drewp@bigasterisk.com
parents:
diff changeset
75 app.add_route("/metrics", handle_metrics)
drewp@bigasterisk.com
parents:
diff changeset
76
drewp@bigasterisk.com
parents:
diff changeset
77 return app
drewp@bigasterisk.com
parents:
diff changeset
78
drewp@bigasterisk.com
parents:
diff changeset
79
27
32cfefe3155b try harder to crash if there's an mqtt error, so k8s does a full restart
drewp@bigasterisk.com
parents: 25
diff changeset
80 uvicorn.run(main, host="0.0.0.0", port=8001, log_level=logging.INFO, factory=True)