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