esphome / feature-requests

ESPHome Feature Request Tracker
https://esphome.io/
411 stars 26 forks source link

S0 output generator #2514

Open ivo7B4 opened 9 months ago

ivo7B4 commented 9 months ago

Describe the problem you have/What new integration you would like S0 signal generator output from ESPHome, as provided by some power meters.

Please describe your use case for this integration and alternatives you've tried: To use the own solar produced energy efficiently, HeatPumps provide some interfaces to provide them the current additionaly produced solary energy. Some HeatPumps have an S0 input such that with an S0 output signal, this information can be provided to the HeatPump. This is much better as the SG (SmartGrid) value only as SG can only be set to one specific threashold but does not provide modulation information to the HeatPump. An alternativ is to use an additional power meter with an S0 signal and this power meter connected not for the currently used energy, but for the energy supplied back to the grid. And to connect this S0 signal to the HeatPump. As I have this information from the inverter of the solar system in HomeAssistant, I clearly would prefer to generate such a signal myself with ESPHome (with providing this value from HomeAssistant to ESPHome). In addition, this also would provide more flexibility, e.g. to keep an offset for some energy reserve in case another device switches on or if there is some variability with the current solar production etc. There are various projects and also ESPHome functionality to read out the S0 signals from power meters to get the current electricty usage. But I haven't seen any project or library support to generate such an S0 signal. Besides the software for this, it also would be great to have a hardware schematic for this project. As far as I have the knowledge, I'm happy to contribute myself.

Additional context Besides that I think this would be a great feature and would optimize the usage costs of electricity, I mainly see the environmental benefit when the energy is used at the time it is produced. Thus, please vote and support this feature request. Thank you!

latonita commented 8 months ago

@ivo7B4 what is the input you have? which component? Its possible to write simple script to generate pulses based on 1 minute energy consumption for example. I dont believe its important to have better resolution.

  1. input - energy consumed/produced for last X seconds period
  2. output - proper amount of pulses during next X seconds period
  3. rinse, repeat

then implementations details - you might fire up all pulses at once (flash x times, need to provide minimum acceptable flash length) or spread it evenly through the period (use pwm)

latonita commented 8 months ago

@ivo7B4 Here is an example I made for blinking the led. You can use optocoupler to switch on/off your s0 input of the heatpump. I used interval as a trigger but you need to use your solar device component and use "on_value:" trigger to get used/produced energy

as per IEC standard for S0 signal - pulse ON shall be at least 30ms + pulse OFF state for at least 30ms as well

esphome:
  name: s0-8266

esp8266:
  board: nodemcuv2

logger:
  level: INFO

globals:
  - id: impulses_to_make
    type: int
    restore_value: no
    initial_value: '0'

switch:
  - platform: gpio
    id: s0
    pin: GPIO02
    inverted: true
  - platform: template
    id: s0_generator
    optimistic: true
    on_turn_on:
      - while:
          condition: 
            lambda: return id(impulses_to_make) > 0;
          then:
            - switch.turn_on: s0
            - delay: 40ms
            - switch.turn_off: s0
            - delay: 40ms
            - lambda: id(impulses_to_make)--;
      - switch.turn_off: s0_generator

interval:
  - interval: 15s
    then:
      - lambda: |- 
          // check how many energy used since last check
          // and calculate how many flashes to add to the queue
          // bigger intervals - less errors, but lower update rate for external device
          // shorter intervals - more accumulated errors
          //
          // assume we would like to pretend we are power meter with 1000 imp/kwh
          // it means 1 Wh = 1 impulse
          // if delta energy used is 25 Wh, then we need to do 25Wh * 1 = 25 impulses
          id(impulses_to_make) += 25; 
          ESP_LOGI("main","We need to flash %d times",id(impulses_to_make));
          if (!id(s0_generator).state) 
            id(s0_generator).turn_on();
ivo7B4 commented 8 months ago

@ivo7B4 what is the input you have? which component? Its possible to write simple script to generate pulses based on 1 minute energy consumption for example. I dont believe its important to have better resolution.

  1. input - energy consumed/produced for last X seconds period
  2. output - proper amount of pulses during next X seconds period
  3. rinse, repeat

then implementations details - you might fire up all pulses at once (flash x times, need to provide minimum acceptable flash length) or spread it evenly through the period (use pwm)

@latonita thank you for your questions and your example! As this S0 output won't be used to count the energy, but mainly to inform e.g. a heatpump (or other devices that get from an S0 signal the currently supplied energy to the grid), I think it's easier to take the current power to the grid (and more responsive to e.g. changes, as it's based on the latest power information) and to calculate the S0 low duration based on the assumption that the power to the grid stays on average the same until the next update, which should be sufficient if this update is done frequently enough. I've meanwhile started to implement an embedded SW implementation directly on an ESP32 (with MQTT interface to HomeAssistant), where I provide this power information whenever I have an update and then calculate the corresponding S0 Signal. I'd still prefer an ESPhome solution due to the additonal functionalities, such as directly OTA updates etc, but I'm not sure whether I can achieve these dynamic low period durations with ESPhome. P.S.: I also think an ESP32 is better as the S0 Signal is specified up to max. 20mA. And depending on the Optocoupler, you need a similar current on the GPIO. And the ESP32 has higher max. current as an ESP8266, as far as I know.

ivo7B4 commented 8 months ago

@ivo7B4 Here is an example I made for blinking the led. You can use optocoupler to switch on/off your s0 input of the heatpump. I used interval as a trigger but you need to use your solar device component and use "on_value:" trigger to get used/produced energy

as per IEC standard for S0 signal - pulse ON shall be at least 30ms + pulse OFF state for at least 30ms as well

esphome:
  name: s0-8266

esp8266:
  board: nodemcuv2

logger:
  level: INFO

globals:
  - id: impulses_to_make
    type: int
    restore_value: no
    initial_value: '0'

switch:
  - platform: gpio
    id: s0
    pin: GPIO02
    inverted: true
  - platform: template
    id: s0_generator
    optimistic: true
    on_turn_on:
      - while:
          condition: 
            lambda: return id(impulses_to_make) > 0;
          then:
            - switch.turn_on: s0
            - delay: 40ms
            - switch.turn_off: s0
            - delay: 40ms
            - lambda: id(impulses_to_make)--;
      - switch.turn_off: s0_generator

interval:
  - interval: 15s
    then:
      - lambda: |- 
          // check how many energy used since last check
          // and calculate how many flashes to add to the queue
          // bigger intervals - less errors, but lower update rate for external device
          // shorter intervals - more accumulated errors
          //
          // assume we would like to pretend we are power meter with 1000 imp/kwh
          // it means 1 Wh = 1 impulse
          // if delta energy used is 25 Wh, then we need to do 25Wh * 1 = 25 impulses
          id(impulses_to_make) += 25; 
          ESP_LOGI("main","We need to flash %d times",id(impulses_to_make));
          if (!id(s0_generator).state) 
            id(s0_generator).turn_on();

@latonita , thank you for your example! Please see my previous comments. And based on this example, I see that I need to get a better knowledge about the lambda logic/functionality in ESPhome.

latonita commented 7 months ago

@ivo7B4 Yesterday I needed to make an emulator of electricity meter pulsing its light. This is something I came up. You set current "Power" from hass UI (hardcoding default value) and then it generates impulses like normal device will do - with proper delay. It doesnt take real consumption but just makes proper signal frequency.

todo if needed:

esphome:
  name: power-meter-emulator
  on_loop:
    then:
      - lambda: |-
          static uint32_t last_time = 0;
         // 1600 imp/kWh =
          uint32_t pulse_width_ms = 1000*(3600*1000/1600)/(id(req_power).state);

          if ((pulse_width_ms) > 0) {
            uint32_t now = millis();
            if (now - last_time > (pulse_width_ms)) {
                last_time = now;
                id(out_power_pulse).turn_on();
                delay(30);
                id(out_power_pulse).turn_off();
                ESP_LOGD("loop", "pulse_width_ms: %d", (pulse_width_ms));
            }
          }
esp32:
  board: esp32dev
  framework:
#    type: esp-idf
    type: arduino

# esp8266:
#   board: nodemcuv2

logger:
  level: DEBUG

globals:
  - id: total_pulses
    type: int
    restore_value: false
    initial_value: '0'
  - id: pulse_width_ms
    type: int
    restore_value: false
    initial_value: '0'

number:
  - platform: template
    id: req_power
    name: "Requested power"
    optimistic: true
    min_value: 0
    max_value: 2000
    step: 50
    initial_value: 0

output:
  - platform: gpio
    id: out_power_pulse
    pin: GPIO18
    inverted: false

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  reboot_timeout: 5min
  power_save_mode: NONE
  fast_connect: true
api:
  password: !secret api_password

ota:
  password: !secret ota_password

web_server:
  port: 80
  auth:
    username: !secret web_user
    password: !secret web_password