Mercurial > code > home > repos > light-bridge
comparison light_bridge.py @ 0:5a77696c6dab
start
author | drewp@bigasterisk.com |
---|---|
date | Sun, 28 Jan 2024 15:32:18 -0800 |
parents | |
children | 42a494b8ee1a |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:5a77696c6dab |
---|---|
1 """ | |
2 replaces a lot of mqtt_to_rdf and rdf_to_mqtt | |
3 """ | |
4 import asyncio | |
5 from dataclasses import dataclass | |
6 from functools import partial | |
7 import json | |
8 import logging | |
9 | |
10 import background_loop | |
11 from patchablegraph import PatchableGraph | |
12 from patchablegraph.handler import GraphEvents, StaticGraph | |
13 from rdflib import Namespace | |
14 from starlette.applications import Starlette | |
15 from starlette.requests import Request | |
16 from starlette.responses import JSONResponse | |
17 from starlette.routing import Route | |
18 from starlette_exporter import PrometheusMiddleware, handle_metrics | |
19 from sse_starlette.sse import EventSourceResponse | |
20 | |
21 EX = Namespace('http://example.com/') | |
22 | |
23 logging.basicConfig(level=logging.INFO) | |
24 log = logging.getLogger() | |
25 | |
26 | |
27 class Color(str): | |
28 | |
29 def to_js(self): | |
30 return self | |
31 | |
32 | |
33 @dataclass | |
34 class Light: | |
35 name: str | |
36 address: str | |
37 online: bool | |
38 colorRequest: Color | |
39 colorMessage: dict | |
40 colorCurrent: Color | |
41 latencyMs: float | |
42 | |
43 def to_js(self): | |
44 return { | |
45 'light': { | |
46 'name': self.name, | |
47 'address': self.address, | |
48 'online': self.online, | |
49 'colorRequest': self.colorRequest.to_js(), | |
50 'colorMessage': self.colorMessage, | |
51 'colorCurrent': self.colorCurrent.to_js(), | |
52 'latencyMs': self.latencyMs, | |
53 } | |
54 } | |
55 | |
56 | |
57 class Lights: | |
58 _d: dict[str, Light] = {} | |
59 | |
60 def add(self, d: Light): | |
61 self._d[d.name] = d | |
62 | |
63 def byName(self, name: str) -> Light: | |
64 return self._d[name] | |
65 | |
66 async def changes(self): # yields None on any data change | |
67 while True: | |
68 yield None | |
69 await asyncio.sleep(1) | |
70 | |
71 def to_js(self): | |
72 return {'lights': [d.to_js() for d in sorted(self._d.values(), key=lambda r: r.name)]} | |
73 | |
74 | |
75 async def output(lights: Lights, request: Request) -> JSONResponse: | |
76 light = lights.byName(request.query_params['light']) | |
77 return JSONResponse(light.to_js()) | |
78 | |
79 | |
80 async def table(lights: Lights, req: Request) -> EventSourceResponse: | |
81 | |
82 async def g(): | |
83 async for ping in lights.changes(): | |
84 yield json.dumps(lights.to_js()) | |
85 await asyncio.sleep(1) | |
86 | |
87 return EventSourceResponse(g()) | |
88 | |
89 | |
90 def main(): | |
91 lights = Lights() | |
92 lights.add(Light('do-desk', 'topic1', True, Color('#ff0000'), {'r': 255}, Color('#000000'), 100)) | |
93 lights.add(Light('do-desk2', 'topic2', True, Color('#ff00ff'), {'r': 255}, Color('#000000'), 200)) | |
94 graph = PatchableGraph() | |
95 app = Starlette(debug=True, | |
96 routes=[ | |
97 Route('/api/output', partial(output, lights), methods=['PUT']), | |
98 Route('/api/table', partial(table, lights)), | |
99 Route('/api/graph', StaticGraph(graph)), | |
100 Route('/api/graph/events', GraphEvents(graph)), | |
101 ]) | |
102 | |
103 app.add_middleware(PrometheusMiddleware, app_name='light-bridge') | |
104 app.add_route("/metrics", handle_metrics) | |
105 # app.state.loop = background_loop.loop_forever(lambda first_run=False: update(graph), 1) | |
106 | |
107 return app | |
108 | |
109 | |
110 app = main() |