wip-3
This commit is contained in:
@@ -1,167 +1,164 @@
|
||||
use std::{collections::LinkedList, thread::JoinHandle};
|
||||
use core::str;
|
||||
use std::{borrow::BorrowMut, collections::{HashMap, LinkedList}, thread::JoinHandle};
|
||||
|
||||
use esp_idf_svc::mqtt::client::{EspMqttClient, MqttClientConfiguration};
|
||||
use esp_idf_svc::mqtt::client::{EspMqttClient, EventPayload, MqttClientConfiguration};
|
||||
use log::Log;
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use crate::{events::{Event, EventBus, System as SystemNS}, prop_id, properties::{PropertyID, Variant}, render::props::Output as OutputNS, scenes::props::Scenes as SceneNS, task::Task};
|
||||
use crate::{events::{Event, EventBus, System as SystemNS}, properties::{NamespaceKey, PropertyID, PropertyKey, Variant}, render::props::Output as OutputNS, scenes::props::Scenes as SceneNS, task::{Environment, Task}};
|
||||
use crate::platform::props::Board as BoardNS;
|
||||
use paste::paste;
|
||||
|
||||
struct HADevice {
|
||||
prefix: String,
|
||||
unique_id: String
|
||||
device_id: String,
|
||||
scenes: Vec<String>
|
||||
}
|
||||
|
||||
impl HADevice {
|
||||
fn new(component: &str, chip_id: u64, name: &str) -> Self {
|
||||
fn new(device_id: String, scenes: Vec<String>) -> Self {
|
||||
HADevice {
|
||||
// eg: homeassistant/sensor/0BADCOFFEE/fps
|
||||
unique_id: format!("{:X}-{}", chip_id, name),
|
||||
prefix: format!("homeassistant/{}/renderbug-rs/{:X}-{}", component, chip_id, name)
|
||||
device_id,
|
||||
scenes
|
||||
}
|
||||
}
|
||||
|
||||
fn topic(&self, name: &str) -> String {
|
||||
format!("{}/{}", self.prefix, name)
|
||||
fn topic(&self, key: &str) -> String {
|
||||
format!("renderbug/{}/{}", self.device_id, key)
|
||||
}
|
||||
|
||||
fn command_topic(&self) -> String {
|
||||
self.topic("command")
|
||||
}
|
||||
|
||||
fn state_topic(&self) -> String {
|
||||
self.topic("state")
|
||||
}
|
||||
|
||||
fn device_config_topic(&self) -> String {
|
||||
format!("homeassistant/device/renderbug-rs-{}/config", self.device_id)
|
||||
}
|
||||
|
||||
fn registration(&self) -> Value {
|
||||
let components: HashMap<String, Value> = self.scenes.iter().map(|f| {
|
||||
let scene_id = format!("renderbug_{}_scene_{}", self.device_id, f);
|
||||
(scene_id.clone(), json!({
|
||||
"p": "scene",
|
||||
"unique_id": scene_id,
|
||||
"payload_on": json!({"namespace": SceneNS::Namespace, "key": SceneNS::Current.key, "value": f}).to_string(),
|
||||
"name": f
|
||||
}))
|
||||
}).collect();
|
||||
json!({
|
||||
"~": self.prefix,
|
||||
"stat_t": "~/state",
|
||||
"unique_id": self.unique_id,
|
||||
"stat_t": self.state_topic(),
|
||||
"cmd_t": self.command_topic(),
|
||||
"dev": {
|
||||
"name": "Renderbug-rs ESP32",
|
||||
"name": format!("Renderbug-rs ESP32 {}", self.device_id),
|
||||
"mdl": "Renderbug-rs ESP32",
|
||||
"sw": "",
|
||||
"mf": "Phong Robotics",
|
||||
"ids": [self.unique_id]
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct HAScene {
|
||||
prefix: String,
|
||||
unique_id: String
|
||||
}
|
||||
|
||||
impl HAScene {
|
||||
fn new(chip_id: u64, name: &str) -> Self {
|
||||
HAScene {
|
||||
// eg: homeassistant/sensor/0BADCOFFEE/fps
|
||||
unique_id: format!("{:X}-{}", chip_id, name),
|
||||
prefix: format!("homeassistant/scene/renderbug-rs/{:X}-{}", chip_id, name)
|
||||
}
|
||||
}
|
||||
|
||||
fn topic(&self, name: &str) -> String {
|
||||
format!("{}/{}", self.prefix, name)
|
||||
}
|
||||
|
||||
fn registration(&self) -> Value {
|
||||
json!({
|
||||
"~": self.prefix,
|
||||
"stat_t": "~/state",
|
||||
"cmd_t": "~/command",
|
||||
"unique_id": self.unique_id,
|
||||
"payload_on": "on",
|
||||
"dev": {
|
||||
"name": "Renderbug-rs ESP32",
|
||||
"mdl": "Renderbug-rs ESP32",
|
||||
"sw": "",
|
||||
"mf": "Phong Robotics",
|
||||
"ids": [self.unique_id]
|
||||
}
|
||||
"identifiers": [self.device_id]
|
||||
},
|
||||
"origin": {
|
||||
"name": "renderbug-rs"
|
||||
},
|
||||
"cmps": components
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MqttTask {
|
||||
client: Option<EspMqttClient<'static>>,
|
||||
conn_thread: Option<JoinHandle<()>>,
|
||||
fps_sensor: Option<HADevice>
|
||||
ha_device: Option<HADevice>
|
||||
}
|
||||
|
||||
impl MqttTask {
|
||||
pub fn new() -> Self {
|
||||
MqttTask {
|
||||
conn_thread: None,
|
||||
client: None,
|
||||
fps_sensor: None
|
||||
ha_device: None
|
||||
}
|
||||
}
|
||||
|
||||
fn start_mqtt(&mut self, bus: &EventBus) {
|
||||
fn start_mqtt(&mut self, env: &mut Environment) {
|
||||
log::info!("Starting MQTT");
|
||||
let chip_id: u64 = bus.properties().get(BoardNS::ChipID).unwrap().into();
|
||||
let chip_id: u64 = env.get_property(BoardNS::ChipID).unwrap();
|
||||
|
||||
self.fps_sensor = Some(HADevice::new("sensor", chip_id, "output-fps"));
|
||||
|
||||
let (client, mut conn) = EspMqttClient::new(
|
||||
let mut client_bus = env.bus.clone();
|
||||
self.client = Some(EspMqttClient::new_cb(
|
||||
"mqtt://10.0.0.2:1883",
|
||||
&MqttClientConfiguration {
|
||||
client_id: Some(&format!("{:X}", chip_id)),
|
||||
..Default::default()
|
||||
}
|
||||
).unwrap();
|
||||
log::info!("Connected!");
|
||||
},
|
||||
move |evt| {
|
||||
match evt.payload() {
|
||||
EventPayload::Received { id, topic, data, details } => {
|
||||
log::info!("got event id={} topic={:?} data={:?} details={:?}", id, topic, str::from_utf8(data), details);
|
||||
let props: HashMap<String, Variant> = serde_json::from_slice(data).unwrap();
|
||||
let ns: String = props.get("namespace").unwrap().to_owned().into();
|
||||
let key: String = props.get("key").unwrap().to_owned().into();
|
||||
let value: Variant = props.get("value").unwrap().clone();
|
||||
let all = client_bus.properties().all_props();
|
||||
let prop_id = all.iter().find(|f| {
|
||||
f.key.0 == key && f.namespace.0 == ns
|
||||
});
|
||||
|
||||
self.conn_thread = Some(std::thread::Builder::new()
|
||||
.stack_size(6000)
|
||||
.spawn(move || {
|
||||
conn.next().unwrap();
|
||||
}).unwrap());
|
||||
self.client = Some(client);
|
||||
client_bus.set_property(SystemNS::Idle, false);
|
||||
|
||||
match prop_id {
|
||||
None => log::warn!("Could not find property {} in {}!", key, ns),
|
||||
Some(id) => client_bus.set_property(id.clone(), value),
|
||||
}
|
||||
},
|
||||
EventPayload::Connected(_) => {
|
||||
log::info!("MQTT is online!");
|
||||
client_bus.set_property(props::MQTT::Online, true);
|
||||
},
|
||||
EventPayload::Disconnected => {
|
||||
log::info!("MQTT is offline!");
|
||||
client_bus.set_property(props::MQTT::Online, false);
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
).unwrap());
|
||||
log::info!("Connected!");
|
||||
}
|
||||
}
|
||||
|
||||
impl Task for MqttTask {
|
||||
fn start(&mut self, bus: &mut EventBus) {
|
||||
bus.set_property(props::MQTT::Online, false);
|
||||
}
|
||||
|
||||
let chip_id = bus.properties().get(BoardNS::ChipID).unwrap().into();
|
||||
self.fps_sensor = Some(HADevice::new("sensor", chip_id, "fps"));
|
||||
fn on_ready(&mut self, bus: &mut EventBus) {
|
||||
let chip_id: u64 = bus.get_property(BoardNS::ChipID).unwrap();
|
||||
let scenes: Vec<String> = bus.get_property(SceneNS::All).unwrap();
|
||||
log::info!("Setting up scenes: {:?}", scenes);
|
||||
self.ha_device = Some(HADevice::new(format!("{:X}", chip_id), scenes));
|
||||
}
|
||||
|
||||
fn on_property_change(&mut self, key: PropertyID, value: &Variant, bus: &mut EventBus) {
|
||||
match (key, value) {
|
||||
(prop_id!(SystemNS::NetworkOnline), Variant::Boolean(true)) => {
|
||||
(SystemNS::NetworkOnline, Variant::Boolean(true)) => {
|
||||
log::info!("Registering with MQTT");
|
||||
|
||||
let chip_id = bus.properties().get(BoardNS::ChipID).unwrap().into();
|
||||
|
||||
self.start_mqtt(bus);
|
||||
|
||||
if let Some(ref mut client) = self.client {
|
||||
if let Some(ref sensor) = self.fps_sensor {
|
||||
client.enqueue(
|
||||
&sensor.topic("config"),
|
||||
esp_idf_svc::mqtt::client::QoS::AtLeastOnce,
|
||||
false,
|
||||
sensor.registration().to_string().as_bytes()
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
let scenes: Vec<Variant> = bus.properties().get(SceneNS::All).unwrap().into();
|
||||
for scene in scenes.iter() {
|
||||
let scene_name: String = scene.clone().into();
|
||||
let scene_device = HAScene::new(chip_id, scene_name.as_str());
|
||||
client.enqueue(
|
||||
&scene_device.topic("config"),
|
||||
esp_idf_svc::mqtt::client::QoS::AtLeastOnce,
|
||||
false,
|
||||
scene_device.registration().to_string().as_bytes()
|
||||
).unwrap();
|
||||
}
|
||||
log::info!("MQTT should be online!");
|
||||
|
||||
bus.set_property(props::MQTT::Online, true);
|
||||
}
|
||||
},
|
||||
(prop_id!(OutputNS::FPS), Variant::UInt(fps)) => {
|
||||
(props::MQTT::Online, Variant::Boolean(true)) => {
|
||||
if let Some(ref mut client) = self.client {
|
||||
if let Some(ref sensor) = self.fps_sensor {
|
||||
if let Some(ref device) = self.ha_device {
|
||||
client.enqueue(
|
||||
&device.device_config_topic(),
|
||||
esp_idf_svc::mqtt::client::QoS::AtLeastOnce,
|
||||
false,
|
||||
device.registration().to_string().as_bytes()
|
||||
).unwrap();
|
||||
log::info!("Subscribing to {}", device.command_topic());
|
||||
client.subscribe(&device.command_topic(), esp_idf_svc::mqtt::client::QoS::AtLeastOnce).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
/*(prop_id!(OutputNS::FPS), Variant::UInt(fps)) => {
|
||||
if let Some(ref mut client) = self.client {
|
||||
if let Some(ref sensor) = self.ha_device {
|
||||
client.enqueue(
|
||||
&sensor.topic("state"),
|
||||
esp_idf_svc::mqtt::client::QoS::AtLeastOnce,
|
||||
@@ -170,7 +167,7 @@ impl Task for MqttTask {
|
||||
).unwrap();
|
||||
}
|
||||
}
|
||||
},
|
||||
},*/
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use esp_idf_svc::{eventloop::{EspSubscription, EspSystemEventLoop, System}, hal::modem::Modem, netif::IpEvent, nvs::{EspNvsPartition, NvsDefault}, sntp::{EspSntp, SyncStatus}, wifi::{AuthMethod, ClientConfiguration, Configuration, EspWifi, WifiEvent}};
|
||||
|
||||
use crate::{events::{EventBus, System as SystemNS}, properties::Variant, task::Task, time::Periodically};
|
||||
use crate::{events::{EventBus, System as SystemNS}, properties::Variant, task::{Environment, Task}, time::Periodically};
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
@@ -83,22 +83,22 @@ impl Task for WifiTask {
|
||||
self.connect();
|
||||
}
|
||||
|
||||
fn on_tick(&mut self, bus: &mut EventBus) {
|
||||
fn on_tick(&mut self, env: &mut Environment) {
|
||||
if self.connection_check.tick() {
|
||||
if bus.properties().get(SystemNS::NetworkOnline).unwrap() == Variant::Boolean(true) {
|
||||
if env.get_property(SystemNS::NetworkOnline).unwrap() {
|
||||
match self.ntp.get_sync_status() {
|
||||
SyncStatus::Completed => bus.set_property(SystemNS::TimeSync, true),
|
||||
_ => bus.set_property(SystemNS::TimeSync, false)
|
||||
SyncStatus::Completed => env.set_property(SystemNS::TimeSync, true),
|
||||
_ => env.set_property(SystemNS::TimeSync, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn stop(&mut self, bus: &mut EventBus) {
|
||||
fn stop(&mut self, env: &mut Environment) {
|
||||
log::info!("Stopping wifi");
|
||||
self.wifi_sub.take().unwrap();
|
||||
self.ip_sub.take().unwrap();
|
||||
self.disconnect();
|
||||
bus.set_property(SystemNS::NetworkOnline, false);
|
||||
env.set_property(SystemNS::NetworkOnline, false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user