Skip to content

Commit e939c6b

Browse files
authored
Merge pull request #2 from netz39/spaceapi
Add SpaceAPI entry, observation and return JSON
2 parents ba5c7ae + 20a3a76 commit e939c6b

File tree

6 files changed

+159
-3
lines changed

6 files changed

+159
-3
lines changed

.env.template

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
11
PORT=8080
2+
MQTT_BROKER=mqtt.local
3+
MQTT_PORT=1883
4+
5+
MQTT_TOPIC_STATUS=SpaceAPI/isOpen
6+
MQTT_TOPIC_LASTCHANGE=SpaceAPI/lastChange

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
Configuration is done using environment variables:
1010

1111
* `PORT`: Target port when used with docker-compose (default `8080`)
12+
* `MQTT_BROKER`: MQTT broker server (default `mqtt`)
13+
* `MQTT_PORT`: MQTT broker port (default `1883`)
14+
* `MQTT_TOPIC_STATUS`: MQTT topic to listen for status messages (default `status`)
15+
* `MQTT_TOPIC_LASTCHANGE`: MQTT topic to listen for last change messages (default `lastchange`)
16+
1217

1318
### Run with Docker
1419

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pytest==7.1.2
22
pytest-asyncio==0.19.0
33
tornado==6.4.1
4-
isodate==0.6.0
4+
isodate==0.6.0
5+
paho-mqtt==2.1.0

src/SpaceApiEntry.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
class SpaceApiEntry:
2+
@staticmethod
3+
def create_netz39():
4+
entry = SpaceApiEntry(
5+
space="Netz39",
6+
logo="https://wiki.netz39.de/_media/resources:public_relations:logo:netz39_logo_2013-07-11.png",
7+
url="https://www.netz39.de/",
8+
address="Leibnizstr. 32, 39104 Magdeburg, Germany",
9+
lat=52.119561,
10+
lon=11.629398,
11+
icon_open="https://www.netz39.de/open.png",
12+
icon_closed="https://www.netz39.de/closed.png"
13+
)
14+
entry.add_contact("email", "kontakt@netz39.de", is_issue_channel=True)
15+
entry.add_contact("twitter", "@netz39", is_issue_channel=True)
16+
entry.add_contact("ml", "list@netz39.de", is_issue_channel=True)
17+
entry.add_contact("jabber", "lounge@conference.jabber.n39.eu")
18+
19+
entry.add_feed("blog", "rss", "https://www.netz39.de/feed/")
20+
entry.add_feed("calendar", "ical", "https://www.netz39.de/feed/eo-events/")
21+
22+
return entry
23+
24+
TEMPLATE = {
25+
"api": "0.13",
26+
"state": {
27+
"open": True,
28+
"lastchange": 0,
29+
"trigger_person": "",
30+
"message": "",
31+
},
32+
"contact": {},
33+
"issue_report_channels": [],
34+
"feeds": {}
35+
}
36+
37+
def __init__(self, space, logo, url, address, lat, lon, icon_open, icon_closed):
38+
self.data = self.TEMPLATE.copy()
39+
self.data.update({
40+
"space": space,
41+
"logo": logo,
42+
"url": url,
43+
"location": {
44+
"address": address,
45+
"lat": lat,
46+
"lon": lon
47+
},
48+
"state": {
49+
"icon": {
50+
"open": icon_open,
51+
"closed": icon_closed
52+
}
53+
}
54+
})
55+
56+
def add_contact(self, key, value, is_issue_channel=False):
57+
self.data["contact"][key] = value
58+
if is_issue_channel:
59+
self.data["issue_report_channels"].append(key)
60+
61+
def add_feed(self, feed, schema, url):
62+
self.data["feeds"][feed] = {
63+
"type": schema,
64+
"url": url
65+
}
66+
67+
def set_is_open(self, is_open):
68+
self.data["state"]["open"] = is_open
69+
70+
def set_lastchange(self, lastchange):
71+
self.data["state"]["lastchange"] = lastchange

src/SpaceStatusObserver.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import paho.mqtt.client as mqtt
2+
3+
class SpaceStatusObserver:
4+
def __init__(self, broker, port, topic_status, topic_lastchange, space_api_entry):
5+
self.broker = broker
6+
self.port = int(port)
7+
self.topic_status = topic_status
8+
self.topic_lastchange = topic_lastchange
9+
self.space_api_entry = space_api_entry
10+
11+
self.client = mqtt.Client()
12+
self.client.on_connect = self.on_connect
13+
self.client.on_disconnect = self.on_disconnect
14+
self.client.on_message = self.on_message
15+
16+
def on_connect(self, client, _userdata, _flags, rc):
17+
print(f"Connected with result code {rc}")
18+
for topic in [self.topic_status, self.topic_lastchange]:
19+
print(f"Subscribing to topic {topic}")
20+
client.subscribe(topic)
21+
22+
def on_disconnect(self, client, userdata, rc):
23+
print(f"Disconnected with result code {rc}")
24+
if rc != 0:
25+
print("Unexpected disconnection. Reconnecting...")
26+
self.client.reconnect()
27+
28+
def on_message(self, client, userdata, msg):
29+
print(f"Message received on topic {msg.topic}: {msg.payload.decode()}")
30+
self.on_message_callback(msg.topic, msg.payload.decode())
31+
32+
def on_message_callback(self, topic, message):
33+
if topic == self.topic_status:
34+
self.space_api_entry.set_is_open(message == "true")
35+
elif topic == self.topic_lastchange:
36+
self.space_api_entry.set_lastchange(int(message))
37+
38+
def start(self):
39+
self.client.connect(self.broker, self.port, 60)
40+
self.client.loop_start()
41+
42+
def stop(self):
43+
self.client.loop_stop()
44+
self.client.disconnect()
45+
46+
def get_space_api_entry(self):
47+
return self.space_api_entry.data

src/app.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
import json
1717

18+
from src.SpaceApiEntry import SpaceApiEntry
19+
from src.SpaceStatusObserver import SpaceStatusObserver
1820

1921
startup_timestamp = datetime.now()
2022

@@ -71,11 +73,23 @@ def get(self):
7173
self.finish()
7274

7375

74-
def make_app():
76+
class SpaceAPIHandler(tornado.web.RequestHandler, ABC):
77+
# noinspection PyAttributeOutsideInit
78+
def initialize(self, observer):
79+
self.observer = observer
80+
81+
def get(self):
82+
self.set_header("Content-Type", "application/json")
83+
self.write(json.dumps(self.observer.get_space_api_entry(), indent=4))
84+
self.finish()
85+
86+
87+
def make_app(observer):
7588
version_path = r"/v[0-9]"
7689
return tornado.web.Application([
7790
(version_path + r"/health", HealthHandler),
7891
(version_path + r"/oas3", Oas3Handler),
92+
(r"/", SpaceAPIHandler, dict(observer=observer)),
7993
])
8094

8195

@@ -91,10 +105,23 @@ def load_env(key, default):
91105

92106
def main():
93107
arg_port = load_env('PORT', 8080)
108+
arg_mqtt_broker_server = load_env('MQTT_BROKER', 'mqtt')
109+
arg_mqtt_broker_port = load_env('MQTT_PORT', 1883)
110+
arg_topic_status = load_env('MQTT_TOPIC_STATUS', 'status')
111+
arg_topic_lastchange = load_env('MQTT_TOPIC_LASTCHANGE', 'lastchange')
94112

95113
# Setup
96114

97-
app = make_app()
115+
observer = SpaceStatusObserver(
116+
broker=arg_mqtt_broker_server,
117+
port=arg_mqtt_broker_port,
118+
topic_status=arg_topic_status,
119+
topic_lastchange=arg_topic_lastchange,
120+
space_api_entry=SpaceApiEntry.create_netz39()
121+
)
122+
observer.start()
123+
124+
app = make_app(observer)
98125
sockets = tornado.netutil.bind_sockets(arg_port, '')
99126
server = tornado.httpserver.HTTPServer(app)
100127
server.add_sockets(sockets)

0 commit comments

Comments
 (0)