Hei,
Har mekka litt for å få HAN-data fra Kamstrup-måleren min (1-fas) inn i Home Assistant.
Bruker ESPHome med en ESP32 for å få inn data, forsøkte med en ESP8266, men den var ikke helt glad i software serieport, derfor måtte jeg ty til 32'en.
Koden er ganske stygg foreløpig, men kanskje det kan hjelpe noen andre på vei:)
Parser dataen ved å lese ut OBIS-koder og så hente tilknyttede data. Ingen CRC-sjekk e.l. da dingsen min ikke ser ut til å lese korrupte data i det hele tatt så langt.
Har lånt en del inspirasjon fra RoarFreds HAN-leser, selv om jeg endte opp med noe ganske annerledes etterhvert:)
ESPHome-konfigurasjonsfil:
esphome:
name: ams
platform: ESP32
board: nodemcu-32s
includes:
mbus.h
wifi:
power_save_mode: light
networks:
- ssid: "LulzNettOppe"
password: ##PASSORD##
- ssid: "LulzNettEkstra"
password: ##PASSORD##
- ssid: "LulzNett"
password: ##PASSORD##
# Enable logging
logger:
level: DEBUG
# Enable Home Assistant API
api:
ota:
uart:
id: uart_bus
tx_pin: GPIO17
rx_pin: GPIO16
baud_rate: 2400
# Example configuration entry
dallas:
- pin: GPIO25
sensor:
- platform: dallas
address: 0xEA0214808622FF28
name: "Temperature Sikringsskap"
- platform: custom
lambda: |-
auto mbus_reader = new MbusReader(id(uart_bus));
App.register_component(mbus_reader);
return {mbus_reader->wattage_sensor, mbus_reader->reactive_power_sensor, mbus_reader->amperage_sensor, mbus_reader->voltage_sensor, mbus_reader->energy_sensor, mbus_reader->reactive_energy_sensor};
sensors:
- name: "AMS Wattage"
unit_of_measurement: kW
accuracy_decimals: 3
filters:
- multiply: 0.001
- name: "AMS Reactive Power"
unit_of_measurement: VAr
accuracy_decimals: 0
internal: true
- name: "AMS Amperage"
unit_of_measurement: A
accuracy_decimals: 2
filters:
- multiply: 0.01
- name: "AMS Voltage"
unit_of_measurement: V
accuracy_decimals: 0
- name: "AMS Hourly Energy"
unit_of_measurement: kWh
accuracy_decimals: 3
filters:
- multiply: 0.01
- name: "AMS Hourly Reactive Energy"
unit_of_measurement: kVArh
accuracy_decimals: 3
internal: true
filters:
- multiply: 0.01
mbus.h:
#include "esphome.h"
class MbusReader : public Component, public uart::UARTDevice, public Sensor {
public:
MbusReader(uart::UARTComponent *parent) : uart::UARTDevice(parent) {}
uint8_t temp_byte = 0;
uint8_t *temp_byte_pointer = &temp_byte;
uint8_t uart_buffer_[512]{0};
uint16_t uart_counter = 0;
char uart_message[550];
char temp_string[10];
char obis_code[32];
char temp_obis[10];
uint32_t obis_value = 0;
float wattage = 0;
float amperage = 0;
float voltage = 0;
float energy = 0;
Sensor *wattage_sensor = new Sensor();
Sensor *amperage_sensor = new Sensor();
Sensor *voltage_sensor = new Sensor();
Sensor *energy_sensor = new Sensor();
Sensor *reactive_power_sensor = new Sensor();
Sensor *reactive_energy_sensor = new Sensor();
void setup() override {
}
void loop() override {
bool have_message = read_message();
}
bool read_message() {
while(available() >= 1) {
read_byte(this->temp_byte_pointer);
if(temp_byte == 126) {
if(uart_counter > 2) {
uart_buffer_[uart_counter] = temp_byte;
uart_counter++;
uart_message[0] = '\0';
strcpy(uart_message, "");
for (uint16_t i = 0; i < uart_counter && i < 256; i++) {
//sprintf(temp_string, "%02X", uart_buffer_[i]);
//strncat(uart_message, temp_string, 2);
if(uart_buffer_[i-1] == 9 && uart_buffer_[i] == 6) {
obis_code[0] = '\0';
strcpy(obis_code, "");
for (uint16_t y = 1; y < 6; y++) {
sprintf(temp_obis, "%d.", uart_buffer_[i + y]);
strcat(obis_code, temp_obis);
}
sprintf(temp_obis, "%d", uart_buffer_[i + 6]);
strcat(obis_code, temp_obis);
ESP_LOGV("uart", "OBIS code found: %s message length: %d", obis_code, uart_buffer_[i + 7]);
obis_value = 0;
if(uart_buffer_[i + 7] == 6) {
for(uint8_t y = 0; y < 4; y++) {
obis_value += (long)uart_buffer_[i + 8 + y] << ((3-y) * 8);
}
} else if(uart_buffer_[i + 7] == 18) {
for(uint8_t y = 0; y < 2; y++) {
obis_value += (long)uart_buffer_[i + 8 + y] << ((1-y) * 8);
}
}
if(strcmp(obis_code, "1.1.1.7.0.255") == 0) {
ESP_LOGV("uart", "Wattage: %d", obis_value);
wattage_sensor->publish_state(obis_value);
} else if (strcmp(obis_code, "1.1.31.7.0.255") == 0) {
ESP_LOGV("uart", "Amperage: %d", obis_value);
amperage_sensor->publish_state(obis_value);
} else if (strcmp(obis_code, "1.1.32.7.0.255") == 0) {
ESP_LOGV("uart", "Voltage: %d", obis_value);
voltage_sensor->publish_state(obis_value);
} else if (strcmp(obis_code, "1.1.1.8.0.255") == 0) {
ESP_LOGV("uart", "Energy Usage Last Hour: %d", obis_value);
energy_sensor->publish_state(obis_value);
} else if (strcmp(obis_code, "1.1.4.7.0.255") == 0) {
ESP_LOGV("uart", "Reactive Power: %d", obis_value);
reactive_power_sensor->publish_state(obis_value);
} else if (strcmp(obis_code, "1.1.4.8.0.255") == 0) {
ESP_LOGV("uart", "Reactive Power Last Hour: %d", obis_value);
reactive_energy_sensor->publish_state(obis_value);
} else {
ESP_LOGV("uart", "Unknown OBIS %s, value: %d", obis_code, obis_value);
}
}
//strncat(uart_message, " ", 1);
}
ESP_LOGV("uart", "%d length received", uart_counter);
//ESP_LOGI("uart", "%d length received: %s", uart_counter, uart_message);
ESP_LOGV("uart", "Message length: %d", uart_message[3]);
uart_counter = 0;
uart_message[0] = '\0';
strcpy(uart_message, "");
} else {
uart_counter = 0;
}
}
uart_buffer_[uart_counter] = temp_byte;
uart_counter++;
}
return false;
}
};