Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions HomeDicator/core/config/common/esphome.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ esphome:

platformio_options:
build_unflags: -Werror=all
lib_deps:
- ArduinoJson

on_boot:
- priority: 800.0
Expand Down
1 change: 1 addition & 0 deletions HomeDicator/core/config/common/fonts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ font:
"\U000F0F91", # mdi:wardrobe-outline
"\U000F111C", # mdi:window-shutter
"\U000F111E", # mdi:window-shutter-open
"\U000F058E", # mdi:WaterPercent
]


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@ esp32:
flash_size: 8MB
framework:
type: esp-idf
version: 5.2.2
platform_version: 6.7.0
sdkconfig_options:
CONFIG_ESPTOOLPY_FLASHSIZE_8MB: y
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: y
CONFIG_ESP32S3_DATA_CACHE_64KB: y
CONFIG_SPIRAM_FETCH_INSTRUCTIONS: y
CONFIG_SPIRAM_RODATA: y

CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG: n # Disable to use PIN 19,20 as UART to RP2040
psram:
mode: octal
speed: 80MHz
Expand Down
30 changes: 30 additions & 0 deletions components/json_uart/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
This implements reading the sensors from the SenseCAP Indicator D1S via the UART connection from the hard-wired RP2040 2nd MCU.

This doesn't work with the stock firmware on the RP2040, you've to flash https://github.com/HomeDicator/RP2040-Firmware to the RP2040 using https://platformio.org/.

```yaml
# example configuration:

sensor:
- platform: json_uart
name: "CO2 Level"
key: "scd4x.co2"
unit_of_measurement: "ppm"
icon: "mdi:molecule-co2"
accuracy_decimals: 0

uart_id: uart_rp2040
- platform: json_uart
name: "Temperature"
key: "scd4x.temp"
unit_of_measurement: "°C"
icon: "mdi:thermometer"

uart_id: uart_rp2040
- platform: json_uart
name: "Humidity"
key: "scd4x.humidity"
unit_of_measurement: "%"
icon: "mdi:water-percent"
uart_id: uart_rp2040
```
Empty file.
94 changes: 94 additions & 0 deletions components/json_uart/json_uart.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include "json_uart.h"
#include "esphome/core/log.h"
#include "esphome/core/application.h"
#include "esphome/core/helpers.h"
#include <ArduinoJson.h>
#include <vector>
#include <sstream>

namespace esphome {
namespace json_uart {

static const char *TAG = "json_uart.sensor";
std::string json_data;


void JsonUartSensor::setup() {
}

void JsonUartSensor::loop() {
// Read JSON data from UART
std::string raw_data;
while (this->available()) {
uint8_t c;
this->read_byte(&c);
if (c == '\n') {
// Store the latest line
json_data = raw_data;
raw_data.clear(); // Clear the buffer after storing the line
} else {
raw_data += static_cast<char>(c); // Cast to char before appending
}
}
}

void JsonUartSensor::update() {
if (json_data.empty()) {
ESP_LOGW(TAG, "No data received from UART yet");
return;
}

ESP_LOGD(TAG, "Updating sensor with JSON data: %s", json_data.c_str());
parse_json_data(json_data);
}

void JsonUartSensor::dump_config() {
ESP_LOGCONFIG(TAG, "JSON UART custom sensor");
ESP_LOGCONFIG(TAG, " Key: %s", key_.c_str());
ESP_LOGCONFIG(TAG, " Unit of Measurement: %s", unit_of_measurement_.c_str());
}

std::vector<std::string> split(const std::string &s, char delimiter) {
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(s);
while (std::getline(tokenStream, token, delimiter)) {
tokens.push_back(token);
}
return tokens;
}

void JsonUartSensor::parse_json_data(const std::string &json_data) {
// Parse the JSON data and extract the value for the given key
ESP_LOGD(TAG, "Parsing JSON data: %s", json_data.c_str());
StaticJsonDocument<1024> doc;
auto error = deserializeJson(doc, json_data);
if (error) {
ESP_LOGW(TAG, "Failed to parse JSON data: %s", error.c_str());
return;
}

JsonObject root = doc.as<JsonObject>();
std::vector<std::string> keys = split(key_, '.');
JsonObject current = root;
for (size_t i = 0; i < keys.size(); ++i) {
if (!current[keys[i].c_str()].is<JsonObject>() && i != keys.size() - 1) {
ESP_LOGW(TAG, "Key %s not found in JSON data", key_.c_str());
return;
}
if (i == keys.size() - 1) {
if (!current[keys[i].c_str()].is<float>()) {
ESP_LOGW(TAG, "Key %s does not contain a float value", key_.c_str());
return;
}
float value = current[keys[i].c_str()].as<float>();
ESP_LOGD(TAG, "Parsed value for key %s: %f", key_.c_str(), value);
this->publish_state(value);
} else {
current = current[keys[i].c_str()].as<JsonObject>();
}
}
}

} // namespace json_uart
} // namespace esphome
26 changes: 26 additions & 0 deletions components/json_uart/json_uart.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include "esphome/components/sensor/sensor.h"
#include "esphome/core/component.h"
#include "esphome/components/uart/uart.h" // Correct header for UARTDevice

namespace esphome {
namespace json_uart {

class JsonUartSensor : public sensor::Sensor, public PollingComponent, public uart::UARTDevice {
public:
void setup() override;
void loop() override;
void update() override;
void dump_config() override;
void set_key(const std::string &key) { key_ = key; }
void set_unit_of_measurement(const std::string &unit) { unit_of_measurement_ = unit; }

protected:
std::string key_;
std::string unit_of_measurement_;
void parse_json_data(const std::string &json_data);
};

} // namespace json_uart
} // namespace esphome
21 changes: 21 additions & 0 deletions components/json_uart/sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor as sensor_component, uart
from esphome.const import UNIT_EMPTY, ICON_EMPTY

json_uart_ns = cg.esphome_ns.namespace("json_uart")

JsonUartSensor = json_uart_ns.class_("JsonUartSensor", sensor_component.Sensor, cg.PollingComponent, uart.UARTDevice)

CONFIG_SCHEMA = sensor_component.sensor_schema(
JsonUartSensor, unit_of_measurement=cv.string, icon=ICON_EMPTY, accuracy_decimals=1
).extend({
cv.Required("key"): cv.string,
}).extend(cv.polling_component_schema("10s")).extend(uart.UART_DEVICE_SCHEMA)

async def to_code(config):
var = await sensor_component.new_sensor(config)
await cg.register_component(var, config)
await uart.register_uart_device(var, config)
cg.add(var.set_key(config["key"]))
cg.add(var.set_unit_of_measurement(config["unit_of_measurement"]))