commit da19f6cf8fde9a0691ac598140f25f149988bca5 Author: Michal Sladecek Date: Wed Oct 25 21:54:46 2023 +0200 First implementation diff --git a/img/ha_output.png b/img/ha_output.png new file mode 100644 index 0000000..782b9c7 Binary files /dev/null and b/img/ha_output.png differ diff --git a/img/pnp.png b/img/pnp.png new file mode 100644 index 0000000..d8b8599 Binary files /dev/null and b/img/pnp.png differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..a3f5de5 --- /dev/null +++ b/readme.md @@ -0,0 +1,27 @@ +# Solareco ESPHome implementation + +There is possible to easily promote all values from Solareco regulator, which are served in ascii format via UART on **P1BT/LAN** connector (baudrate 115200) to your Home assistant assistant server. + +ESP8266 ([chosed NodeMCU v3](https://www.aliexpress.com/item/1005004893534216.html)) will make a really simple implementation together with [ESPHome](https://esphome.io/). + +### First implementation +Firstly you need to install ESP home to your Home assistant instance. There are multiple ways how to do that, the official is [here](https://www.home-assistant.io/integrations/esphome/). + +When is your ESPHome extension installed to your home assistant server, connect NodeMCU board via USB to your computer and click on ***+ new device***. Fill the name **solareco-meter**, choose **Esp8266** and new card with "solareco-meter" should appear in your ESPHome extension. Click on **Edit** == code editor will show up. **Copy the encryption key, and passwords. Than take example code from [src/solareco-meter.yaml](src/solareco-meter.yaml), inset all the keys and password you copied from previous step and paste the whole code back to the editor. Than click to Save and Install** + +After the installation you will see your sensor online, but not serving any data. + + +### Implementation with Solareco HW +To be able to get your data from Solareco, you need to connect already prepared device with the **P1BT/LAN** pin header. +- Solareco device having 5V logic on mentioned LAN connector. We will use 5V VCC to power up pur NodeMCU and one extra **PNP transistor for level shifting (feel free to use different type of level shifter)** of the UART TX signal from 5V to 3V3 which ESP is compatible with. Example of the PNP level shifter: + +![pnp simple level shifter](img/pnp.png) + +- - Connect VCC from LAN connector to **VIN** pin on your NodeMCU +- - Connect GND from LAN connector to **GND** pin on your NodeMCU +- - Connect TX from LAN connector to level shifter mentioned earlier and its output to pin **D7** on your NodeMCU + +All the values from the UART should appear in your Home assistant as a new device. The values are updating every ~15s (possible to set in .yaml file) + +![sensor otput](img/ha_output.png) diff --git a/src/solareco-meter.yaml b/src/solareco-meter.yaml new file mode 100644 index 0000000..215aa67 --- /dev/null +++ b/src/solareco-meter.yaml @@ -0,0 +1,188 @@ +esphome: + name: solareco-meter + # friendly_name: SolarEco_meter + +esp8266: + board: esp01_1m + +# Enable logging +logger: + baud_rate: 115200 + +# Enable Home Assistant API +api: + encryption: + key: "" + +ota: + password: "" + +wifi: + ssid: !secret wifi_ssid + password: !secret wifi_password + + # Enable fallback hotspot (captive portal) in case wifi connection fails + ap: + ssid: "Solareco-Meter Fallback Hotspot" + password: "" + +# global variables for downsampling and enerhy spikes +globals: + - id: latest_energy_value + type: int + restore_value: no + initial_value: '-1' + - id: downsample_counter + type: int + restore_value: no + initial_value: '0' + +captive_portal: + +# There is not possible to have UART read without having custom function in ESPHome, +# but there is a shortcut how to do that for easy applications with UARTDebug log functions +uart: + baud_rate: 115200 + tx_pin: 15 + rx_pin: 13 + id: uart_2 + debug: + direction: RX + dummy_receiver: true + after: + delimiter: "\n" + sequence: + - lambda: |- + UARTDebug::log_string(direction, bytes); + char m[20]; + char p[20]; + int fan = 0; + int dc = 0; + int ac = 0; + int l = 0; + int solar = 0; + int required_voltage = 0; + int voltage = 0; + int current = 0; + int power = 0; + int frequency = 0; + int temperature = 0; + int boiler_temperature = 0; + int pulse_width = 0; + int energy = 0; + std::string str(bytes.begin(), bytes.end()); + + // old PCB data format.... split the data from format (b'M:4 P:1:1 R:0 F:0 U:168 168V 838mA 140W 50Hz 30C 594us 252Wh\n') + // new PCB data format (b'M:4:6 P:23:10 F1 DC1 AC0 0L 224S 224U 225V 7068mA 1586W 0:39C 7289us 3014Wh\n') + if (sscanf(str.c_str(), "M:%s P:%s F%d DC%d AC%d %dL %dS %dU %dV %dmA %dW %d:%dC %dus %dWh", m, p, &fan, &dc, &ac, &l, &solar, &required_voltage, &voltage, ¤t, &power, &boiler_temperature, &temperature, &pulse_width, &energy ) == 15) { + // check wrong peaks + if(id(latest_energy_value) > 1 && id(latest_energy_value) > energy ){ + // new energy value is smaller than old one, no reset because its higher than 1 + return; + } + // fill up current energy value + id(latest_energy_value) = energy; + id(downsample_counter) += 1; + // send every 15th sample font not that frequent communication + if(id(downsample_counter) % 15 == 0){ + // publish the data + id(SOLAR_fan).publish_state(fan); + id(SOLAR_dc).publish_state(dc); + id(SOLAR_ac).publish_state(ac); + id(SOLAR_l).publish_state(l); + id(SOLAR_solar).publish_state(solar); + id(SOLAR_required_voltage).publish_state(required_voltage); + id(SOLAR_voltage).publish_state(voltage); + id(SOLAR_current).publish_state(current); + id(SOLAR_power).publish_state(power); + id(SOLAR_temperature).publish_state(temperature); + id(SOLAR_boiler_temperature).publish_state(boiler_temperature); + id(SOLAR_pulse_width).publish_state(pulse_width); + id(SOLAR_energy).publish_state(energy); + } + } + +sensor: + - platform: template + name: "SolarEco-Fan" + id: "SOLAR_fan" + update_interval: never + accuracy_decimals: 0 + - platform: template + name: "SolarEco-DC" + id: "SOLAR_dc" + update_interval: never + accuracy_decimals: 0 + - platform: template + name: "SolarEco-AC" # relay, 1 = relay on, 0 relay off + id: "SOLAR_ac" + update_interval: never + accuracy_decimals: 0 + - platform: template + name: "SolarEco-L" + id: "SOLAR_l" + update_interval: never + accuracy_decimals: 0 + - platform: template + name: "SolarEco-Solar voltage" + id: "SOLAR_solar" + unit_of_measurement: 'V' + device_class: voltage + update_interval: never + accuracy_decimals: 1 + - platform: template + name: "SolarEco-Required voltage" + id: "SOLAR_required_voltage" + unit_of_measurement: 'V' + device_class: voltage + update_interval: never + accuracy_decimals: 1 + - platform: template + name: "SolarEco-Voltage" + id: "SOLAR_voltage" + unit_of_measurement: 'V' + device_class: voltage + update_interval: never + accuracy_decimals: 1 + - platform: template + name: "SolarEco-Current" + id: "SOLAR_current" + unit_of_measurement: 'mA' + device_class: current + update_interval: never + accuracy_decimals: 1 + - platform: template + name: "SolarEco-Power" + id: "SOLAR_power" + unit_of_measurement: 'W' + device_class: power + update_interval: never + accuracy_decimals: 1 + - platform: template + name: "SolarEco-Temperature" + id: "SOLAR_temperature" + unit_of_measurement: '°C' + device_class: temperature + update_interval: never + accuracy_decimals: 1 + - platform: template + name: "SolarEco-BoilerTemperature" + id: "SOLAR_boiler_temperature" + unit_of_measurement: '°C' + device_class: temperature + update_interval: never + accuracy_decimals: 1 + - platform: template + name: "SolarEco-Pulse with" + id: "SOLAR_pulse_width" + unit_of_measurement: 'us' + device_class: duration + update_interval: never + accuracy_decimals: 3 + - platform: template + name: "SolarEco-Energy" + id: "SOLAR_energy" + unit_of_measurement: 'Wh' + device_class: energy + state_class: total_increasing + accuracy_decimals: 1