hw10 done, please check

This commit is contained in:
Claudio Maggioni 2023-05-01 17:05:12 +02:00
parent babfc83f4a
commit 2bb1147728
2 changed files with 187 additions and 0 deletions

View file

@ -188,6 +188,7 @@ function toc(str) {
if (token.heading.indexOf("Ex -") >= 0) { if (token.heading.indexOf("Ex -") >= 0) {
token.heading = token.heading.replace("Ex -", `<span class='task'>${task_count}.</span> `); token.heading = token.heading.replace("Ex -", `<span class='task'>${task_count}.</span> `);
task_count++; task_count++;
if (task_count === 13) task_count++; // skip hands-on
} }
// Create a "slugified" id for linking // Create a "slugified" id for linking
@ -459,6 +460,7 @@ renderer.heading = function (text, level, raw, slugger) {
if (text.indexOf("Ex -") >= 0) { if (text.indexOf("Ex -") >= 0) {
text = text.replace("Ex -", `<span class='task'>${task_count}.</span> `); text = text.replace("Ex -", `<span class='task'>${task_count}.</span> `);
task_count++; task_count++;
if (task_count === 13) task_count++; // skip hands-on
} }
// let sec = "<section>" // let sec = "<section>"

View file

@ -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 <span style="background-color: #CCCCCC">like this</span>.
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<boolean> getStatus();
Future<Void> 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<boolean> getStatus() {
return client.subscribe(deviceTopic /* get status message */);
}
@Override
public Future<Void> 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<boolean> getStatus() {
return accessory.getLightbulbPowerState();
}
@Override
public Future<Void> 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 <tupadr3/font-awesome/database>
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 <<user provided>>
[HomeKit smart sensor] as HS <<user provided>>
[HAP-java] as HAP <<external>> #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 <<user provided>>
[MQTT smart sensor] as ZS <<user provided>>
[paho.mqtt.java] as ZIG <<external>> #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)] <<external>> 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 <<external>>
[User and Device DB <$database{scale=0.33}> (PostgreSQL)] <<external>> 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)] <<external>> as TDB
TDBF-TDB
T -( TDBF
}
component "Scenes" as SCENE {
interface " " as SCDBF
[Scene Engine] as SC
[Scene DB <$database{scale=0.33}> (PostgreSQL)] <<external>> 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 # Ex - Physical and Deployment Views