diff --git a/gleam.toml b/gleam.toml index b2e196a..1b60035 100644 --- a/gleam.toml +++ b/gleam.toml @@ -22,6 +22,7 @@ spoke_mqtt_actor = ">= 1.1.1 and < 2.0.0" spoke_tcp = ">= 2.0.0 and < 3.0.0" gleam_erlang = ">= 1.3.0 and < 2.0.0" gleam_otp = ">= 1.2.0 and < 2.0.0" +gleam_json = ">= 3.1.0 and < 4.0.0" [dev_dependencies] gleeunit = ">= 1.0.0 and < 2.0.0" diff --git a/manifest.toml b/manifest.toml index c381e1a..b98204c 100644 --- a/manifest.toml +++ b/manifest.toml @@ -8,6 +8,7 @@ packages = [ { name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" }, { name = "glaml", version = "3.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib", "yamerl"], otp_app = "glaml", source = "hex", outer_checksum = "100CA23F526AB159712A3204D200969571FC43B193736B320C1400D410DEE7AD" }, { name = "gleam_erlang", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "1124AD3AA21143E5AF0FC5CF3D9529F6DB8CA03E43A55711B60B6B7B3874375C" }, + { name = "gleam_json", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "44FDAA8847BE8FC48CA7A1C089706BD54BADCC4C45B237A992EDDF9F2CDB2836" }, { name = "gleam_otp", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "BA6A294E295E428EC1562DC1C11EA7530DCB981E8359134BEABC8493B7B2258E" }, { name = "gleam_stdlib", version = "0.70.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "86949BF5D1F0E4AC0AB5B06F235D8A5CC11A2DFC33BF22F752156ED61CA7D0FF" }, { name = "gleeunit", version = "1.9.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "DA9553CE58B67924B3C631F96FE3370C49EB6D6DC6B384EC4862CC4AAA718F3C" }, @@ -25,6 +26,7 @@ packages = [ envoy = { version = ">= 1.1.0 and < 2.0.0" } glaml = { version = ">= 3.0.2 and < 4.0.0" } gleam_erlang = { version = ">= 1.3.0 and < 2.0.0" } +gleam_json = { version = ">= 3.1.0 and < 4.0.0" } gleam_otp = { version = ">= 1.2.0 and < 2.0.0" } gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" } gleeunit = { version = ">= 1.0.0 and < 2.0.0" } diff --git a/src/config.gleam b/src/config.gleam index 9891a17..3a90c8a 100644 --- a/src/config.gleam +++ b/src/config.gleam @@ -1,9 +1,5 @@ import envoy import glaml -import gleam/dict -import gleam/erlang/node -import gleam/io -import gleam/list import gleam/option.{type Option, None, Some} import gleam/result import simplifile diff --git a/src/readings_broadcaster.gleam b/src/readings_broadcaster.gleam index 840e8e5..1c115eb 100644 --- a/src/readings_broadcaster.gleam +++ b/src/readings_broadcaster.gleam @@ -1,5 +1,5 @@ +import gleam/bit_array import gleam/erlang/process -import gleam/io import gleam/list import gleam/otp/actor import sensors @@ -17,11 +17,13 @@ fn handle_message( state: State, update: mqtt.Update, ) -> actor.Next(State, mqtt.Update) { + echo update case parse_mqtt_update(update) { - Ok(reading) -> { + Ok(readings) -> { // Publish to all subscribers + echo readings list.each(state.subscribers, fn(subscriber) { - process.send(subscriber, reading) + list.each(readings, fn(reading) { process.send(subscriber, reading) }) }) actor.continue(state) } @@ -29,12 +31,20 @@ fn handle_message( } } -fn parse_mqtt_update(update: mqtt.Update) -> Result(sensors.SensorReading, Nil) { - io.println("GOT MQTT MESSAGE!") - echo update - // TODO: Implement parsing logic based on your MQTT topic/payload structure - // For now, return an error - Error(Nil) +fn parse_mqtt_update( + update: mqtt.Update, +) -> Result(List(sensors.SensorReading), Nil) { + case update { + mqtt.ReceivedMessage(topic, payload, _) -> { + let assert Ok(payload_str) = bit_array.to_string(payload) + case topic { + "homeassistant/sensor/bws/node1/state1" -> + Ok(sensors.parse_topic_1(payload_str)) + _ -> Error(Nil) + } + } + _ -> Error(Nil) + } } pub fn start( diff --git a/src/sensors.gleam b/src/sensors.gleam index 9e05cde..ba494df 100644 --- a/src/sensors.gleam +++ b/src/sensors.gleam @@ -1,5 +1,7 @@ +import gleam/dynamic/decode import gleam/float import gleam/io +import gleam/json pub type Sensor { Temperature @@ -25,7 +27,28 @@ pub fn sensor_name(sensor: Sensor) -> String { } } -// homeassistant/sensor/bws/node1/state1 +pub const topic_1: String = "homeassistant/sensor/bws/node1/state1" + +type Topic1Value { + Topic1Value(temp: Float, humidity: Float, pressure: Float) +} + +/// Parses a JSON string into a list of `SensorReading` values. +/// example input string: {"temp":18.84,"humidity":28.690811,"pressure":944.67} +pub fn parse_topic_1(json_string: String) -> List(SensorReading) { + let decoder = { + use temp <- decode.field("temp", decode.float) + use humidity <- decode.field("humidity", decode.float) + use pressure <- decode.field("pressure", decode.float) + decode.success(Topic1Value(temp:, humidity:, pressure:)) + } + let assert Ok(decoded_val) = json.parse(from: json_string, using: decoder) + [ + SensorReading(sensor: Temperature, value: decoded_val.temp), + SensorReading(sensor: Humidity, value: decoded_val.humidity), + SensorReading(sensor: Pressure, value: decoded_val.pressure), + ] +} pub fn print_sensor_reading(reading: SensorReading) -> Nil { let sensor_name = sensor_name(reading.sensor)