JNSwanson / ESP-Home-iBoost

ESPHOME Marlec iboost integration
MIT License
20 stars 2 forks source link

Remotely varying iBoost diversion to account for factors other than detected solar surplus #13

Open srchild opened 3 months ago

srchild commented 3 months ago

I'm looking for a way to automatically deactivate my iBoost+ solar diversion when certain conditions are met, probably via a Home Assistant automation.

If I can do this via ESP-Home-iBoost then that would be great. There isn't an obvious way to achieve that from within ESP-Home-iBoost though I wonder whether it might be possible to flood the iBoost+ with messages telling it there is no surplus solar, i.e. simulate Sender messages rather than simulating iBoost Buddy messages?

Other thoughts I have had:

Any other suggestions welcome.

8none1 commented 3 months ago
  • insert a 16A relay such as Shelly plus 1 between the power source and the iBoost+ (I suspect that frequent power cycling of the iBoost+ unit is probably not a good idea and also would not be very responsive)

This is what I have done. No harm has come to the iBoost, yet. I've been running this for approx 6 months and it was quite busy over the winter.

srchild commented 3 months ago

Having thought about this a bit further and tinkered a bit I now have some progress but also some new challenges.

For those of you who want to know what I am trying to achieve and why, I've put a writeup at the end of this post (section 3). My scenario will not apply to many, but elements of it may apply to some other situations.

Three sections to this discussion.

  1. Disabling the iBoost

  2. Replacing the iBoost Sender data with Home Assistant calculations

  3. Description of my situation as to why I want to do this.

  4. It is pretty clear that the three methods I listed for disabling iBoost are all viable.

    • Shelly relay to remove power to the iBoost. Disadvantage is potentially a lot of power-cycling of the iBoost, and also a bit sluggish to restart when turned back on (compared to its usual responsiveness to sender information about changes in solar generation and domestic loading)

    • Shelly relay on iBoost output, to simulate water HOT. Disadvantage is the cost of two relays if two outputs are connected. Advantage of rapid clean cycling of heating on/off as required.

    • run Sender on 3.4V DC mains adaptor and switch power on/off using smart socket. I found an old 3V power brick with the appropriate tip (I think it is 2.5mm/0.7mm), and checked the output in case it was too high (glad I did that as one of them, Sony branded, was outputting 5V even though labelled 3V!) If you try this you may need to enlarge the hole in the Sender case or remove the cover as the socket for the power connector is recessed deep into the case. It worked - I was able to disable the iBoost. Disadvantage: sluggish response, firstly as the voltage falls slowly after removing power, presumably due to a high capacity smoothing capacitor in the adaptor, then it takes about another 30s for the iBoost to notice the that the Sender has stopped sending. Turning back on has a much faster response.

Overall, for disabling/enabling iBoost with fastest response, relay(s) on the output(s) seems the best option.

  1. However I realised that there is another need beyond just disabling the iBoost. I also have a need to be able to give the iBoost different data on export than the actual Sender CT clamp measured export kW. There are scenarios (see mine in section 3 of this post) where we may want the iBoost to be guided by different export figures to those that the sender is giving it - I may want to restrict it to lower power consumption than the export figure that the Sender would report, or I may want to allow it to use more power than the export figure that the Sender would report. I realised that I don't just want binary enabled/disabled. I want to be able to control the upper limit of its power draw continuously from zero upwards regardless of Sender information.

It seems that it should be possible for ESP-Home-iBoost (or an additional device programmed along similar principles) to send data to the iBoost that is calculated by Home Assistant and formatted to appear as though it is Sender data coming from the Sender (set third byte of the sent packets to 01). To avoid conflicting messages the Sender could be disabled as per above (switch off Sender psu) when the pseudo-Sender is in use.

  1. By way of background for anyone who is wondering why I want to do this, here is why.

I have a 3-phase power supply. I have three arrays of solar panels (facing East, South, and West), with each array connected to a different phase. With a standard 3-phase meter of the older style which did not net the import/export across the phases I have very often been charged for import on one phase while other phases are exporting.

I have finally managed to get a SMETS2 3-phase meter installed (Aclara). The specification for SMETS2 3-phase meters requires them to net the import and export across the phases, and charge only for the net import. This is good for my situation! For example if I am importing 3kW on one phase but generating 1kW surplus on each of the other two phases then I am charged only for 1kW import instead of 3kW. However it brings other problems in relation the iBoosts.

The iBoosts only know about the phase to which they are connected. If an iBoost detects 3kW surplus solar on its phase then it will draw 3kW. But I might be importing 4kW on another phase which has very low solar generation at that time of day and would prefer to self-consume the 3kW generated on another phase and thereby import only 1kW. Hence my wish to be able to disable the iBoost when load is >= generation so that no generation on any phase is diverted to water heating. This is achievable by measuring loading (with CT clamps at the distribution board) and generation (from my inverter realtime data) and using home assistant to disable solar diversion using one of the methods I mention above.

A different challenge arises when generation > loading and so it would make sense to turn the iBoosts back on. Just turning on in the usual way is not good enough. iBoost may note that its phase has 3kW surplus and so will draw 3kW, overlooking that other phases are net importers and it would be beneficial for the iBoost to draw less. In effect I need to be able to replace the single-phase Sender with a pseudo-Sender which transmits 'faked' (calculated) export data to iBoost taking account of the loading/generation across all three phases instead of just taking account of the phase to which it is connected.

I hope that makes sense to anyone who has read this far. It seems to make sense to me anyway!

srchild commented 3 months ago
  • insert a 16A relay such as Shelly plus 1 between the power source and the iBoost+ (I suspect that frequent power cycling of the iBoost+ unit is probably not a good idea and also would not be very responsive)

This is what I have done. No harm has come to the iBoost, yet. I've been running this for approx 6 months and it was quite busy over the winter.

Thanks. Depending on your need for responsiveness putting the relay(s) on the output(s) might be advantageous to avoid the unit boot up duration each time you restart it.

JNSwanson commented 3 months ago

You might be interested in this: https://openenergymonitor.org/mk2pvrouter/ I did build one once to test. It worked well but due to where my meter is in relation to my immersion, I couldn't use it. There is a 3 phase version also.

srchild commented 3 months ago

You might be interested in this: https://openenergymonitor.org/mk2pvrouter/ I did build one once to test. It worked well but due to where my meter is in relation to my immersion, I couldn't use it. There is a 3 phase version also.

Thank you for reminding me of that. I had totally forgotten about it, though I did consider building it about 3 years ago. I didn't proceed for two reasons. One was that I suspected the electrician who was working on my renovations at the time would refuse to install a home-made device like that! The other was the difficulty and length of cable run (about 20m) required for the CT clamp cables.

I'll keep that in mind as a possible solution. The cable run would be easier now as I have some conduit in place but it would still be just as long a run. This is where the iBoost is helpful with its Sender.

Emulating a Sender using ESP8266 and CC1101 could be useful for some other scenarios besides mine e.g. if someone wants to charge a battery and heat water at the same time they could allow the iBoost to divert only up to a specified maximum which would leave some surplus power for a battery to charge.

I have accurate generation data (better than provided by CT clamps, I expect) from my Enphase Envoys which report the output of each microinverter, and I have Zigbee Tuya 3-phase CT clamp meter reporting to Home Assistant the distribution board loading on each phase. I'm hoping that emulating a Sender ought to be only a smallish (ha ha) sideways step from your ESP-Home-iBoost build and code. Packets transmitted could be asserted as being from the Sender by setting the third byte to 01, and formatted to contain the desired faked export available data. Someone here appears to have decoded the Sender protocol

If I get an opportunity to tinker I'll report back, but it won't happen straightaway.

srchild commented 3 months ago

I've made some good progress on this but not yet success.

I've setup a number helper in HA to transfer the calculated net value of surplus solar across the three phases into ESPhome, where I have made it available to the iboost.h code as a global variable.

To my ESP-Home-iBoost instance I've added a pseudo-sender in the code and disabled the physical Sender. My iBoost+ is responding to this (though not yet satisfactorily). When it is active the "Lost sender" message and red light turns off. Sometimes (but not in a stable manner) the iBoost diverts power, with the blue light flashing and the screen indicating the kW value of the power being diverted.

The problem is that the power being diverted does not correspond very well to the data that I'm sending which indicates the power available. There is some relationship but it is not stable.

If for testing I send a larger stable value such as 9A then the highest values of diversion that I see are higher than when I send a lower stable value such as 2A. The peak diversion figures are approximately correct (actually a little high e.g. 2.75 kW). But within just a few seconds, or perhaps 10-20s, the displayed power diversion suddenly drops by 30-40%, or to just 0.02kW or similar, or switches to water heating OFF (even though I am sending identical data on power available). When it comes back on it may seem to "stick" at a lower power for a while, and never seems to recover back to the correct power level. (Perhaps it would recover if I left if long enough, but I've not bothered trying because clearly the diversion should be stable when the data it is receiving on power available is also stable.)

The way I've implemented it is that in iboost.h I've created a "Sender" section in the main loop. This is essentially a modified copy of the if(addressValid){ ... } of the main loop, using txBuf2 instead of txBuf, changing the third byte to 0x01, and sending 44 byte packet with the last 40 bytes being current (ampere) values. Those 40 elements are constructed as per https://miscsolutions.wordpress.com/2022/10/02/home-energy-management-system-part-2-hacking-the-iboost-protocol/ i.e. the amplitudes of the positive sections of 2 cycles of 50Hz sine wave at 1ms intervals for 40ms. He suggested a multiplier of 9.1, which based on my findings so far may be a little high but not a big deal at this stage.

A packet produced by the physical sender and captured in ESP-Home-iBoost looks like this:

Got packet,b4,f0,01,00,1c,0b,00,0a,0b,05,01,00,00,00,00,00,03,00,00,00,00,02,01,0d,1b,0d,00,08,0c,05,01,00,00,00,00,00,03,00,00,00,00,02,02,0f,,len=44 Signal=-61 LQI=2

A packet produced by my pseudo-sender and captured in ESP-Home-iBoost (a second instance for dev purposes) looks like this:

Got packet,b4,f0,01,00,00,11,20,2c,34,37,34,2c,20,11,00,00,00,00,00,00,00,00,00,00,00,11,20,2c,34,37,34,2c,20,11,00,00,00,00,00,00,00,00,00,00,,len=44 Signal=-57 LQI=1

NB The 00 are in different places in the two strings simply because of phase differences between these two samples so I din't think that is significant. If I look at other samples from the physical sender then the location of zeroes varies naturally (see also the graphs on the article linked above).

I've considered a few possible causes for the instability:

Any comments or suggestions of ways to investigate/fix this instability would be welcome.

Thanks.

srchild commented 3 months ago

I wondered whether there may be a hardware problem with the iBoost to cause the instability in the response, though I don't observe that problem in normal use. I've just retested with different hardware - a different ESP8266 and C1101, and a different iBoost (which happens to be connected to a different phase). The same phenomenon is apparent. The iBoost accepts the data and does some diversion, but responds inconsistently. This time the same data (9Amp) never produced a response above 2.2 kW diversion, vs the 2.75 observed with the previous hardware.

I also tried leaving it running for longer. The same phenomenon continued. The power diversion varied significantly and erratically, including stopping altogether from time to time even though the same value packets (indicating 9A surplus) continued to be sent throughout.

It seems my packets are valid enough to make the iBoost believe it is receiving sender packets (hence the warning of lost sender is turned off), but perhaps not fully valid and hence not interpreted as intended.

srchild commented 3 months ago

I'm putting a pause on this for now. I think the Sender protocol (and perhaps also its interaction with the iBoost) is more complex than I thought.

Looking at this work I thought that it would just be a matter of replicating that packet content (which I have got working) but I think there is more to it than that.

For example, the Sender packets do not appear to contain an import/export flag, so how does the system distinguish between import and export? Clearly it can distinguish that - it responds differently if the CT is reversed, and the Buddy reports on figures in excess of 300W identifying them as either import or export. Perhaps there is a flag, but what/where is it? Perhaps the lack of such a correctly constructed flag in the data that I am sending explains the erratic response to the packets that I have sent.

I have thought of another approach which would bypass this problem. Instead of faking the sender, I could fake the CT clamp, by sending an appropriate voltage/polarity down the line to the Sender to indicate a specific value of import/export, and leave the Sender to encode that data in a protocol which iBoost will understand. Probably this would be possible with a DAC such as on ESP32.

Meantime I'll have another look at mk2pvrouter. That could be viable and could easily be funded by eBaying my three iBoost+. Unfortunately that project has been sold by its English inventor to a French company which publishes all its material including assembly instructions only in French. They have developed it from his design (e.g. changed the 433MHz wireless functions to wifi, but I don't know what else) and so referring to his old website will not fully describe the version that I would buy.

srchild commented 3 months ago

What I've been overlooking is the need to synchronise the faked sender data with the timing of the phase cycles, to enable the iBoost to analyse the Sender data against the waveform of the voltage reaching the iBoost. This is required not only for power factor but also for determining import/export. Lack of overall synchronisation, but with occasional accidental synchronisation, would explain the erratic response that I have seen to my faked data.

Synchronisation would be required whether I fake the Sender or the CT clamp. To attempt to do so would add another whole level of complexity, (e.g. changing this from a 3.3V project to a 230V project!) so I think I'll give up on this unless more inspiration comes along.

srchild commented 2 months ago

I have this working now :)

The overall function established is to be able to vary iBoost+ behaviour in relation to factors other than the solar surplus detected by the Marlec CT clamp and Sender. This is implemented via a small extension to the coding of ESP-Home-iBoost and the addition of a little extra hardware.

  1. I can now set a threshold (minimum solar surplus before diversion starts) of any value I wish via a number helper in Home Assistant.
    • It may be useful to set a higher threshold to reduce the import that the iBoost does due its slow adjustment when available power reduces. This threshold could also be varied via an HA automation e.g. set it higher when there is ample solar generation so no need to run it close to the edge.
    • on the contrary, it may sometimes be useful to run a lower or even negative threshold to ensure that no solar power at all is exported, at the cost of paying for some import. This might apply when solar generation is low and you anticipate that to achieve target tank temperature it will anyway be necessary to import later in the day - you may as well harvest all the surplus solar by running with a negative threshold.
    • a hardware Sender250 is available to buy (£££) from Marlec for those who want to set a higher threshold to accommodate a battery. But I can now set that via a number helper in home Assistant.
  2. if required an iBoost can be temporarily disabled, via a toggle on HA dashboard (or by setting the threshold very high)
  3. if you have more than one iBoost you can allocate surplus solar power between them, e.g. prioritize one over another
  4. My specific use case is to manage a 3-phase installation with a vector summing 3-phase meter and solar PV on each phase, with an iBoost installed on two of these phases. Previously each iBoost could only detect and use surplus power on "it's own" phase. That might allow wasted export (if there is spare power on other phases), or cause unwanted import (if the surplus power on its phase would be better left undiverted so that it can count as export to cancel out import on other phases). My iBoosts are now responsive to the overall solar power surplus available (and also to any import occurring) across all three phases. I have configured one iBoost+ to take priority over the other, i.e. the second iBoost+ is only offered any power once the first is fully powered (or tank hot).
  5. there may be other use cases that I haven't thought of yet.

The general schema is as follows.

Code: I'm happy to share my code if anyone is interested once I've finished tweaking/tuning it. It won't be pretty (this is my first venture into C++ !) but it isn't very complicated so you should be able to follow it (and likely improve on it).

Dibblah1 commented 2 months ago

Code: I'm happy to share my code if anyone is interested once I've finished tweaking/tuning it. It won't be pretty (this is my first venture into C++ !) but it isn't very complicated so you should be able to follow it (and likely improve on it).

Definitely interested in this code! I want to be able to set an export limit of 3.6kW (rather than the default 100w) to take the maximum advantage of our available export, but be able to limit the actual export to that value through dumping to the immersion loads.

srchild commented 2 months ago

Code: I'm happy to share my code if anyone is interested once I've finished tweaking/tuning it. It won't be pretty (this is my first venture into C++ !) but it isn't very complicated so you should be able to follow it (and likely improve on it).

Definitely interested in this code! I want to be able to set an export limit of 3.6kW (rather than the default 100w) to take the maximum advantage of our available export, but be able to limit the actual export to that value through dumping to the immersion loads.

I'll tidy up and annotate the code and upload soon. Remind me if I haven't done it within a week!

Though I'm not sure it will fulfil your need. The problem is the way the iBoost works. If you set an export limit of 3.6kW but generate 5.6kW the code will tell the iBoost to take 2kW but the iBoost will not take that immediately - it will only work up towards that 2kW limit over 30 seconds or more and may never quite get there. During that time you will be exporting more than 3.6kW. If the solar surplus decreases the iBoost will stop diverting and then work up again towards the new limit, so again you will have a period when you are exporting more than 3.6kW.

srchild commented 1 month ago

An amendment to the above. Tuya PC311-Z-TY is only a moderately good choice. It does work for me and integrates with Home Assistant using zigbee2mqtt. But the refresh frequency is not configurable and is quite slow.

Tuya PJ-1203A is a similar device but has refresh frequency configurable as low as 3seconds. I have two PJ-1203A also working under zigbee2mqtt

srchild commented 1 month ago

To install the pseudo-Sender functionality here are the steps and code.

Start with standard iBoost-ESP-Home hardware and code.

EXTRA HARDWARE REQUIRED - 1:

An AC reference source such as an AC PSU like this 12V device:

https://cpc.farnell.com/ideal-power/77db-06-12m/linear-psu-12v-ac-0-5a-6va-6-connectors/dp/PW05856

This is so that the pseudo-Sender packets can be sent at the appropriate point in the AC cycle for them to be interpreted by the iBoost+ as valid Sender packets.

Other low voltage AC output PSU could be used, such as 6V, 9V or 15V etc, but you would need to use different value resistors for the voltage divider.

You will also need to change the resistor values if your ESP8266 ADC accepts maximum 1V. My NodeMCU device accepts up to 3.3V and the values I used were for a 12V AC PSU and a NodeMCU accepting 3.3V on ADC pin.

Make a simple half-wave rectifier circuit using one diode, and a voltage divider using two resistors.

Check your PSU output voltage with an accurate multimeter, and check the output of your voltage divider, making allowance for the output being unsmoothed DC (which means the the peaks will be higher than the mean), so as to avoid damaging your ESP8266. circuit-diagram I used a 1N4005 diode (D1). A lower or higher voltage device such as 1N4001/2/3/4/6/7 would also be OK.

For the voltage divider resistors I used 6.8k Ohm for R1 and 1k Ohm for R2.

Connect two wires to the appropriate ESP8266 pins as per diagram.

NB Given that the AC output is not polarised and the phasing is not marked you have a 50% chance of connecting the AC output of the PSU the "wrong" way around. Be prepared to reverse the AC output connections later if if appears that your AC reference is 180 degrees out of phase when you try to tune the device.

EXTRA HARDWARE REQUIRED - 2:

You will be disabling the Marlec iBoost CT clamp and Sender but you will still need a source of information on your import/export status, and this must be integrated into Home Assistant. If you do not already have such (you may, such as from an inverter or battery supplier, or appliance supplier such as myEnergi) you will need to buy and install something. As an example, but there are others, this Tuya bidirectional energy meter works for me with Home Assistant via Zigbee2MQTT.

https://www.zigbee2mqtt.io/devices/PJ-1203A.html

Install and configure in Home Assistant.

I have myEnergi devices but I found the refresh was not frequent enough whereas the PJ-1203A allows refresh interval to be configured as low as 3 seconds. A refresh interval of 9 seconds or less seems best so that the Sender packets which are sent every 10seconds are updated since the previous sending.

EXTRA CODE REQUIRED

I'm not sure how best to format code here. The 'code' button isn't working for me, and hyphens are appearing as bullets - replace bullets by hyphens!

I'll attach this whole message as a text file in the hope that the formatting of the code is clearer that way.

iboost-sender-writeup.txt

TEMPLATE SENSORS:

Create Home Assistant Template Sensors to report surplus solar current as 'iboost_current_delta' e.g. place the following in templates.yaml

(NB pseudocode as example, adjust to suit your sensors and check code and indentation for validity)

- sensor:
    - name: "Solar available"
      unique_id: 987654321123456789
      unit_of_measurement: "W"
      state: >
        {% set threshold = states('input_number.iboost_threshold') | int(0) %}
        {% set power = states('sensor.meter_power') | int(0) %}
        {% if ((states('sensor.meter_energy_flow') == 'producing') and (power > threshold)) %}
          {% set surplus = power - threshold %}
        {% else %}
          {% set surplus = 0  %}
        {% endif %}
        {{ surplus }}

    - name: iBoost current delta
      unique_id: 123456789987654321
      unit_of_measurement: "A"
      state: >
        {% set voltage = states('sensor.meter_voltage') | float(1) %}
        {% if states('sensor.solar_available') == 0 %}
          {% set iboostcurrentdelta = 0 %}
        {% else %}
          {% set iboostcurrentdelta = (states('sensor.solar_available') | float(2) / voltage ) | float(2) %}
        {% endif %}
        {{ iboostcurrentdelta }}

HELPERS:

Create the following Home Assistant helpers and add them to a card on your dashboard so that you can vary them at will.

input_boolean.iboost_enable

input_number.iboost_calibration, with following parameters

input_number.iboost_threshold

(large minimum and maximum are for testing, for production use typical min/max might be -200 and + 300, with a default of +100)

IBOOST.YAML

After insertions check that indentation is correct

insert at line 33:

globals:
  - id: surplus_solar
    type: float
    restore_value: false
    initial_value: '0'

  - id: calibration_sender
    type: float
    restore_value: false
    initial_value: '0'

  - id: iboost_enable
    type: boolean
    restore_value: false
    initial_value: '1'

insert at line 35:

  - platform: homeassistant
    id: iboost_current_delta
    name: Solar Surplus
    entity_id: sensor.iboost_current_delta
    on_value:
      then:
        - globals.set:
            id: surplus_solar
            value: !lambda return id(iboost_current_delta).state;

  - platform: homeassistant
    id: iboost_calibration
    name: Sender calibration
    entity_id: input_number.iboost_calibration
    on_value:
      then:
        - globals.set:
            id: calibration_sender
            value: !lambda return id(iboost_calibration).state;

insert at line 132:

binary_sensor:
  - platform: homeassistant
    id: iboost_enable
    name: iBoost enable
    entity_id: input_boolean.iboost_enable
    on_state:
      then:
        - globals.set:
            id: iboost_enable
            value: !lambda return id(iboost_enable).state; 

IBOOST.H

insert at line 183:

// used for pseudo-sender
  uint8_t j = 0;
  unsigned long thisMillis = 0;
  unsigned int highestValue = 0;
  unsigned long highestTime = 0;
  unsigned int thisValue = 0;
  unsigned long sendTime = 0;
  float solarValue = 0;
  float yval = 0;
  uint8_t txBuf2[45];
  long phaseOffset = 0;
  long nowTime = 0;

  void referenceAcRead() { 
    thisValue = analogRead(A0); 
    if (thisValue >= highestValue){
      highestValue = thisValue;
      highestTime = thisMillis;
    }
  }

insert the rest of the code at line 374:

// Pseudo-Sender part - Emulate sender packet

    if(addressValid){

// if nearly due to send a 'sender' packet (due every 10000ms) and sending enabled, create and send packet values
      if (((millis() - sendTime) > 9900) && (iboost_enable->value() == 1)) {

        memset(txBuf2, 0, sizeof(txBuf2));

        txBuf2[1] = address[0];
        txBuf2[2] = address[1];  
        txBuf2[3] = 0x01;
        txBuf2[4] = 0x00;   

//check 40ms (2 cycles of 20ms) of mains 50Hz to determine time of peak
        for (j = 0; j < 40; j++) {  
          thisMillis = millis();
          referenceAcRead();
          delay(1);
        }

//create the send time calculated as 
  // rounded current time
  // + modulus of highestTime (time of peak of AC cycle), so that peak of sent data coincide with peak of mains cycle
  // + delay 40ms empirical, calculated to ensure not already in past (e.g. if nowTime%20 = 19 and highestTime%20 = 0), 
  //     but without creating undue delay in case mains is not precisely 50Hz and peak will drift
  // NB synchronisation can be tuned with pos or neg phaseOffset set by calibration_sender value (see below)
        nowTime = millis();
        sendTime = (nowTime - (nowTime%20)) + (highestTime%20) + 40 ;

// convert 'calibration_sender' value (degrees) to radians
//  this is a user-configurable phase shift to tune the Sender data phase
//  18degrees = 1ms
        phaseOffset = calibration_sender->value()*0.0174533;

// wait for precise sending millisecond
        while (sendTime > millis()) {
          delay(1);
        }

// adjust surplus current value offered by multiplying by factor
// factor 9.1 suggested as per https://miscsolutions.wordpress.com/2022/10/02/home-energy-management-system-part-2-hacking-the-iboost-protocol/      
//  9.1. does work but may overshoot, possibly because my CT updates were not frequent enough - 5 works better for me
        solarValue = surplus_solar->value() * 5;

// Create sender data - 
//  requires 40 values representing 1ms intervals for 40ms of 50Hz, i.e. two full cycles
//    - set all to 0 if no export
//    - if there is export, create sine wave values, then set any negative values to 0 

        for (j = 0; j < 40; j++) {
          // #surplus_solar current available for this device, in 1ms increments for 40 values
                 //   sin (2 * PI * 50Hz * loopcounter (1ms intervals) / 1000 (milliseconds)
                 // sin(0.3141593*j)
                 // plus phase shift, add 90deg (1.570796  radians) to bring peak to beginning of output
                 // plus phaseOffset i.e. calibration/tuning value
          if (solarValue < 0) {
            yval = 0;  // if no surplus solar set all vaues to 0
          } else {
            yval =  (solarValue)*sin((0.3141593*j) + 1.570796 - phaseOffset);
          }

          if (yval < 0) {  // set negative values to 0
            yval = 0;
          }

          txBuf2[j+5] = (int)round(yval);
        }

        radio.strobe(CC1101_SIDLE);
        radio.writeRegister(CC1101_TXFIFO, 0x2c); // this is the packet length
        radio.writeBurstRegister(CC1101_TXFIFO, txBuf2 + 1, 44); // write the data to the TX FIFO
        radio.strobe(CC1101_STX);
        delay(5);
        radio.strobe(CC1101_SWOR);
        delay(5);
        radio.strobe(CC1101_SFRX);
        radio.strobe(CC1101_SIDLE);
        radio.strobe(CC1101_SRX);

        Serial.println("Sent Sender packet");  
//        for (int j = 1; j < 45; j++) {
//          sprintf(pbuf, "%02x", txBuf2[j]);
//          Serial.print(pbuf); //packet[j], HEX);
//          Serial.print(",");
//        }  

        highestValue = 0;
        highestTime = 0;
        thisValue = 0;
      }
    }

The file should now end with the original lines 374-376:

  }
};
iBoostBuddy * iBoost;

INSTALL AND RUN

If you want to test it at a time with no solar surplus you can simulate solar surplus by setting a large negative threshold e.g. -2500W. Don't forget to set it back to about +100W after testing.

Give it about 30seconds to settle and you should see "Heating by Solar" with a gradually increasing power.

If iboost_current_delta is showing several amps but heating by solar does not start within 20-30 seconds, or if performance is very erratic, you may need to reverse your AC output cables. You can simulate such a reversal to test it by setting helper input_number.iboost_calibration to 180 degrees.

Once you have confirmed your cabling you can experiment with the calibration setting to tune it, seeing if an offset in either direction improves its responsiveness to iboost_current_delta being available. 18 degrees corresponds to 1ms shift and it seems not very sensitive to small changes. I don't find much difference between -10 to +20 so leaving it at 0 may be OK.

You may need to tweak the code a bit to get it working. I have used different base code because I have two iBoosts and hence have hard-coded the address. I've tried to write code above that should work with the original ESP-Home-iBoost code but have not been able to test it.

no1knows commented 1 month ago

@srchild I don't have an immediate need for this, but may do in future and really appreciate the effort. Thank you!

srchild commented 1 month ago

Thinking further on this, you may need to determine and hard code the address, as I have done.

When the standard ESP-Home-iBoost starts up it listens for packets. Without a physical sender there will be no packets for it to detect and read the address, and so it won't send any packets.

You probably need to run it initially with the physical sender active, monitoring on the terminal to see the packets received, and read the address bytes from them, then hard code the address before you run it without the physical sender operating.

jfdawson commented 1 month ago

Thanks @srchild . I've been thinking about how to do this for a while. I look forward to trying your solution. In the mean time I've found that it is possible to inhibit solar boost by spoofing zero current packets faster than the sender sends them, which does much of what I wanted and requires no additional hardware.

srchild commented 1 month ago

Thanks @srchild . I've been thinking about how to do this for a while. I look forward to trying your solution. In the mean time I've found that it is possible to inhibit solar boost by spoofing zero current packets faster than the sender sends them, which does much of what I wanted and requires no additional hardware.

Yes inhibiting diversion was easier. But besides wanting to inhibit diversion at times, I also needed at other times to be able to increase diversion above that which might seem appropriate when monitoring export on only one phase of a 3-phase installation, hence the extra complexity of the final solution.

This has been working well for me over the recent sunny weather. I have rearranged my CTs to make better use of the more frequent updates available with the PJ-1203A energy meters, and this has enabled better responsiveness and accuracy of solar surplus calculations. In response to this I have increased the multiplier mentioned in the code from 5 to 7 but still find 9.1 to be a bit too high . With a higher multiplier the iBoost takes more current than may be surplus, and the next CT updates shows a surplus of zero and the iBoost stops diverting, and then has to "start again" ramping up from zero but soon stops again because the solar surplus becomes zero again. With the multiplier set to 7 the iBoost seems to reach a steadier level of diversion (when solar output and house load are both stable) and can maintain it showing a surplus available of around 1A without crashing down to zero and then stopping and restarting again.

kingo17rs commented 1 week ago

I used a relay controlled with tasmota/homeassistant to disable the CT clamp. I bought some 3.5 x 1.3 barrel power jacks and panel female jacks and made an extension lead with a Wemos relay device in the middle to cut the circuit, so effectivly the sender sees it as a power cut. It wont vary the output of the iboost its a simple on/off but might be useful for someone. My issue was when I left the house for holidays the water in the cylinder gradually crept up to above 70C which never normally happens as we are drawing it off when we're home.