From 2bb11477286f6db8de5c648bbc5e5de5141c3ec3 Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Mon, 1 May 2023 17:05:12 +0200 Subject: [PATCH] hw10 done, please check --- build.js | 2 + src/sa/model/index.md | 185 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+) diff --git a/build.js b/build.js index a3ccc7b..fbeb5f2 100644 --- a/build.js +++ b/build.js @@ -188,6 +188,7 @@ function toc(str) { if (token.heading.indexOf("Ex -") >= 0) { token.heading = token.heading.replace("Ex -", `${task_count}. `); task_count++; + if (task_count === 13) task_count++; // skip hands-on } // Create a "slugified" id for linking @@ -459,6 +460,7 @@ renderer.heading = function (text, level, raw, slugger) { if (text.indexOf("Ex -") >= 0) { text = text.replace("Ex -", `${task_count}. `); task_count++; + if (task_count === 13) task_count++; // skip hands-on } // let sec = "
" diff --git a/src/sa/model/index.md b/src/sa/model/index.md index da285ab..73c6743 100644 --- a/src/sa/model/index.md +++ b/src/sa/model/index.md @@ -1393,8 +1393,193 @@ Whenever you have a connector you couple together the components and different c } +1. The smart device protocol libraries `HAP-Java` and `paho.mqtt.java` play the role of adapters in the diagram of my architecture. The two components are highlighted in the diagram like this. +2. The mismatch these adapters solve is between the state logic of the devices as handled by the SmartHut Users and Devices component and the way these states are represented and triggered in the MQTT and HomeKit protocol. The two protocol libraries act as a translation layer between the Java runtime of the Users and Devices component and the communication stack required by both protocols. +3. The `Homekit Device Wrapper` and `MQTT Device Wrapper` have been introduced in the diagram. +4. As SmartHut should handle by design different IoT protocols, no standard interfaces could play a role in the architecture. The wrappers (and in particular the _SmartHut to \[library\]_) adapters) I introduced aim to create a common ground between IoT protocols to handle the devices in a standardized fashion whitin SmartHut. +5. One important coupling facet decision between in the architecture is the discovery coupling between the web "engine" components. When deploying, I either aim to have a static configuration file where all Web Interface root endpoints are enumerated (one per component) to allow both a monolith and polylith installation of SmartHut according to the user's needs (an example of a project that allows this kind of decision at deployment is the Matrix protocol implementation [Dendrite](https://github.com/matrix-org/dendrite)). +6. Here I provide examples of how the adapters in the MQTT Wrapper and Homekit wrapper adapt + the communication between the SmartHut Users and Devices engine component and the respective protocols. I envision a common interface specification for both protocols, enumerating the actions of each smart device. Here's an example for a smart light with only on/off capabilities: + + ```java + interface Light { + Future getStatus(); + Future setStatus(boolean turnOn); + } + ``` + + Then, here's a high level implementation for the MQTT protocol, which is code to be included in the SmartHut to paho.mqtt.java adapter: + + ```java + class MQTTLight extends Light { + private final MqttClient client; + private final String deviceTopic; + + public MQTTLight(@Inject MqttClient client, String deviceTopic) { + this.client = client; + this.deviceTopic = deviceTopic; + } + + @Override + public Future getStatus() { + return client.subscribe(deviceTopic /* get status message */); + } + + @Override + public Future setStatus(boolean turnOn) { + return client.publish(deviceTopic, new MqttMessage(turnOn)); + } + } + ``` + + and here's a high level implementation for the Homekit protocol, to be included in the SmartHut to HAP-java adapter: + + ```java + class HAPLight extends Light { + private final LightBulbAccessory accessory; + + public HAPLight(LightBulbAccessory accessory) { + this.accessory = accessory; + } + + public static HAPLight discover(String deviceId) { + /** here create the lightbulb accessory object from the given + device id, call constructor */ + } + + @Override + public Future getStatus() { + return accessory.getLightbulbPowerState(); + } + + @Override + public Future setStatus(boolean turnOn) { + return accessory.setLightBulbPowerState(turnOn); + } + } + ``` +7. Coupling between the engine components of Smarthut would be to introduce Zeroconf clients and servers in all engine components and allow auto-discovery in an initial setup phase, which would delay discovery coupling at runtime an allow for more flexible deployments. However, this would slightly complicate the implementation of the frontend as UDP/broadcast connections are harder to implement in a web-based interface. +```puml +@startuml +skinparam componentStyle rectangle + +!include + +title Smarthut.sm Logical View + +interface " " as DIF +interface " " as TF +interface " " as SCF +interface " " as SHAF +interface " " as SZAF + +component "Homekit Device Wrapper" as IOTHK { + interface " " as HDF + interface " " as HSF + interface " " as HAPF + + [HomeKit smart device] as HD <> + [HomeKit smart sensor] as HS <> + [HAP-java] as HAP <> #CCCCCC + [SmartHut to HAP-java adapter] as SHA + + HAP--HAPF + HD--HDF + HS--HSF + HAPF)--SHA + SHA--SHAF +} + +component "MQTT Device Wrapper" as IOTMQ { + interface " " as ZDF + interface " " as ZSF + interface " " as ZIGF + + [MQTT smart device] as ZD <> + [MQTT smart sensor] as ZS <> + [paho.mqtt.java] as ZIG <> #CCCCCC + [SmartHut to paho.mqtt.java adapter] as SZA + + ZD--ZDF + ZS--ZSF + ZIG--ZIGF + SZA--SZAF + ZIGF)--SZA +} + +component "User Interface" as UIC { + interface " " as WSCF + + [User Interface] as UI + [WebSockets API (JavaScript)] <> as WSC + + WSCF)--UI + WSC--WSCF +} + +component "Users and Devices" as DEV { + interface " " as DIDBF + + interface " " as WSSF + + [Device Engine] as DI + + note left of DI: Already implemented using Spring Boot + + [javax.websocket API] as WSS <> + [User and Device DB <$database{scale=0.33}> (PostgreSQL)] <> as DIDB + + HDF )-- HAP + HSF )-- HAP + ZDF )-- ZIG + ZSF )-- ZIG + + DI--(WSSF + WSSF--WSS + SHAF )-- DI + SZAF )-- DI + DIDBF-DIDB + DI -( DIDBF +} + +component "Triggers and Automations" as TRIG { + interface " " as TDBF + + [Trigger and Automation Engine] as T + [Trigger and Automation DB <$database{scale=0.33}> (PostgreSQL)] <> as TDB + + TDBF-TDB + T -( TDBF +} + +component "Scenes" as SCENE { + interface " " as SCDBF + + [Scene Engine] as SC + [Scene DB <$database{scale=0.33}> (PostgreSQL)] <> as SCDB + + SCDBF-SCDB + SC -( SCDBF +} + +DI--DIF +TF--T +SCF--SC +WSS <..> WSC: WebSocket protocol (RFC 6455) +DI --( TF +T --( SCF +DIF )-- SC +DIF )-- UI +UI --( SCF +UI --( TF + +skinparam monochrome true +skinparam shadowing false +skinparam defaultFontName Courier +@enduml +``` # Ex - Physical and Deployment Views