Add spaceapid update endpoint
All checks were successful
docker-image / docker (push) Successful in 1m30s

Configure the device name and the update endpoint to report open status to spaceapid.
This commit is contained in:
Stefan Bethke 2025-06-13 18:17:09 +02:00
commit 7cb930be38
4 changed files with 30 additions and 2 deletions

View file

@ -18,6 +18,8 @@ All configuration is handled through environment variables.
| `IDINVITE_OIDC_SCOPE` | `["openid", "email", "profile"]` | JSON list of OIDC scopes to request. The OIDC IDP will need to send the group attribute. |
| `IDINVITE_OIDC_USER_ATTR` | `email` | The attribute to use as the user ID. |
| `HMDOORIS_REQUIRES_GROUP` | - | Set to require users to be a member of this groups. |
| `HMDOORIS_SPACEAPI_OPEND_NAME` | - | Name of the device to send `spaceapid` updates for |
| `HMDOORIS_SPACEAPI_OPEN_URL` | - | URL for the `spaceapid` open update endpoint. |
| `HMDOORIS_URL` | `http://localhost:3000` | URL of the application, used to construct links to itself. |
### Required Group
@ -34,6 +36,14 @@ RaspberryMatic. If you are using a private certificate, you will need to use `HM
the HTTP client to a suitable CA certificate. Setting the variable to `false` will disable certificate verification.
Alternatively, you can use plain `http`.
### SpaceAPI
[spaceapid](https://git.hamburg.ccc.de/CCCHH/spaceapid) can be used to provide data
for [SpaceAPI](https://spaceapi.io), and it's open update endpoint can be used to report the open status of a space. By
setting `HMDOORIS_SPACEAPI_OPEND_NAME` to the name of the lock on the main door, and `HMDOORIS_SPACEAPI_OPEN_URL` to the
update endpoint URL hmdooris can update the open status whenever it changes. Add the username and password in the url,
in the `https://user:pass@hostname.tld` format. If you do not set the name, no updates will be sent.
## Managing the CCU certificate
If you want to talk to the RaspberryMatic/CCU-Jack and you are using a self-signed certificate (which is the default),

View file

@ -28,6 +28,8 @@ class AppConfig:
self.ccujack_certificate_path = getenv('HMDOORIS_CCUJACK_CERTIFICATE_PATH', None)
self.ccujack_username = getenv('HMDOORIS_CCUJACK_USERNAME', None)
self.ccujack_password = getenv('HMDOORIS_CCUJACK_PASSWORD', None)
self.spaceapid_open_name = getenv('HMDOORIS_SPACEAPI_OPEND_NAME', None)
self.spaceapid_open_url = getenv('HMDOORIS_SPACEAPI_OPEN_URL', 'https://spaceapi.hamburg.ccc.de/state/open')
if self.debug is not None and self.debug.lower not in ('0', 'f', 'false'):
self.debug = True

View file

@ -39,7 +39,10 @@ auth = BottleOIDC(app, config={
websocket_clients = WebSocketClients()
bottle_helpers = BottleHelpers(auth, group=config.requires_group, allowed=config.allowed)
update_poller = UpdatePoller(websocket_clients, ccujack, 1 if config.debug else 0.1)
update_poller = UpdatePoller(websocket_clients, ccujack,
update_delay=1 if config.debug else 0.1,
spaceapid_open_name=config.spaceapid_open_name,
spaceapid_open_url=config.spaceapid_open_url)
@app.route("/static/<filepath>")

View file

@ -3,16 +3,23 @@ import logging
from threading import Thread
from time import sleep
import requests
from hmdooris.ccujack import CCUJack
from hmdooris.websocketcomm import WebSocketClients
class UpdatePoller:
def __init__(self, wsc: WebSocketClients, ccu: CCUJack, update_delay = 1.0):
def __init__(self, wsc: WebSocketClients, ccu: CCUJack,
update_delay = 1.0,
spaceapid_open_name=None,
spaceapid_open_url=None):
self.wsc = wsc
self.ccu = ccu
self.current = {}
self.update_delay = update_delay
self.spaceapid_open_name = spaceapid_open_name
self.spaceapid_open_url = spaceapid_open_url
self.log = logging.getLogger(__name__)
Thread(target=self.run, daemon=True).start()
@ -33,6 +40,7 @@ class UpdatePoller:
for lock_id, value in new.items():
if force or lock_id not in self.current or self.current[lock_id] != value:
update.append(value)
self.spaceapid_open_update(value)
data = {
"locks": update,
}
@ -42,3 +50,8 @@ class UpdatePoller:
def send_locks(self, force=False):
self.wsc.send(self.get_locks())
def spaceapid_open_update(self, lock):
if self.spaceapid_open_name is None:
return
requests.put(self.spaceapid_open_url, data=lock["status"]=="UNLOCKED")