* remove duplicated #defines. this is most probably a merge error from
2024-01-16, as evidenced by 63205f88b, which added these duplicates.
* sort values by upstream and downstream projects. add a comment which
tells us in the future where OpenDTU-OnBattery-specific values start.
currently this is only supported by the Pylontech battery provider, as
it reports a "charge battery immediately" alarm. this will also be
implemented by the JK BMS provider, and possibly also by the smart shunt
provider.
the method will be used to determine whether or not to start charging
the battery using the (Huawei) charger.
by default and until this change, we assumed that the inverter
controlled by the DPL is powered by a battery. not all users have a
battery in their system. they still use the DPL to achieve net-zero
export. those users can now tell the DPL that their inverter is powered
by solar modules rather than a battery and the DPL will behave
accordingly.
the update frequency of Victron MPPT charger data, the battery Soc, the
huawei charger power, and the power meter differ from one another, and
differ in particular from the inverter update frequency.
the OnBattery-specific data is now handled in a new method, outside the
upstream code, which merely call the new function(s). the new function
will update the websocket independently from inverter updates. also, it
adds the respective data if it actually changed since it was last
updated through the websocket.
for the webapp to be able to recover in case of errors, all values are
also written to the websocket with a fixed interval of 10 seconds.
we previously only called commitPowerLimit() if the desired limit
changed such that the change was bigger than the hysteresis. we found
that if the limit update was not received and the desired limit would
not change much, the limit of the inverter was wrong for a long time.
to mitigate this, we introduced re-sending the limit update every 60
seconds, regardless of what the limit reported by the inverter was at
that time.
if the power-up command was not received, we also would repeat it only
once every 60 seconds.
this leads to a new kind of staleness and the actual inverter state was
still not matching the desired state.
this new approach effectively adds an additional control loop at the
start of the DPL loop(). that new function compares the requested
inverter state to the actual reported state. it sends updates (limit
update or power on state) until the desired inverter state is reached,
or until a (hard-coded) timeout occurs.
this approach also allows us to send power-up, power-down, and limit
update commands independent from one another and in a particular order.
this should make sure that the inverter is in the desired state even if
conditions change slowly and commands were not received as expected.
the DPL is interested in the battery's voltage to make decisions about
draining the battery or letting it charge (if the user opts to use
voltage thresholds rather than SoC thresholds). using the DC input
voltage reported by the inverter under control has disadvantages:
* the data might be quite old due to the communication protocol
implementation. more inverters being polled means even more lag. the
connection being wireless makes this even worse, due to the need
to retry the occasional lost packet, etc.
* the data is not very accurate, since the DC input of the inverter is
actually some cabling and a couple of junctions away from the actual
battery. this voltage drop can mostly only be estimated and is worse
with higher load. the load correction factor is there to mitigate
this, but it has its own problems and is cumbersome to calibrate.
instead, this change aims to use more accurate battery voltage readings,
if possible. the DPL now prefers the voltage as reported by the BMS,
since it is for sure the closest to the battery of all measuring points
and measures its voltage accurately regardless of the load (the voltage
reading will still drop with higher loads, but this will be only due to
the battery's internal resistance, not that of cabling or junctions). if
no BMS voltage reading is available, the DPL will instead use the charge
controller's voltage reading, as it is available with much higher
frequency and is assumed to be more accurate as it offers a resolution
of 10mV. only if none of these two sources can be used, the inverter DC
input voltage is assumed as the battery voltage.
closes#655.
the Victron SmartShunt communicates the SoC value in permille. this
should be displayed in the web UI accordingly. this is a good excuse to
fully move ownership of the SoC value to the BatteryStats base class and
add a precision indicator variable. this is required to be set each time
a derived class (a battery provider) wants to update the SoC value. the
precision is then used when populating the JSON data for the web UI
(live view).
related to #573.
in the respective context, the DPL only needs to be sure that the SoC
value is not outdated. it should not even care about other values
reported by the battery interface. hence, the isValid() method shall be
concerned with the SoC value timestamp only. the method is renamed for
clarity.
this extends the MqttBattery implementation by an additional topic which
allows to subscribe to receive battery voltage readings through the MQTT
broker. similar to the battery SoC topic, this allows to import a
critical battery data point for the DPL, in case the user chooses to use
voltage thresholds rather than SoC thresholds to control the DPL. if an
otherwise incompatible BMS is available which publishes the battery pack
voltage through MQTT, this can now be used to feed accurate voltage
readings to the DPL.
the BatteryStats base class shall be able to tell the total battery pack
voltage. for that reason, and to avoid code duplication, the voltage is
now handled in the base class and treated as a datum that is common to
all battery providers.
unfortunately, the battery SoC values reported by battery BMSs are
unreliable, at least for some users, or at least without regular
(manual) full charge cycles to calibrate the BMS. it offers great
advantages to connect OpenDTU-OnBattery to a BMS (MQTT publishing of
values, Home Assistent integration, etc.), but previously the users
were then forced to configure the DPL by SoC values.
this change allows to configure the DPL such that SoC values are
ignored. instead, the voltage limits are used to make DPL decisions, as
if no SoC was available in the first place.
the SoC related setting are hidden from the DPL settings view if SoC
values are configured to be ignored.
closes#654.
* pylontech HA integration: remove unused method/variable
* make MqttHandlePylontechHassClass::publishConfig() private.
there are no outside users of that method.
* rename to MqttHandleBatteryHass
* battery HA integration: merge methods and bring back forceUpdate().
even though the forceUpdate() method was not in use before, it makes
sense to implement it and use it when the battery config changes.
rather than controlling a separate flag, it now changes the _doPublish
flag of the class, which also triggers publishing the device config to
Home Assistant when an MQTT connection problem was detected. since
both situations are now handled similarly, we can merge the loop() and
publishConfig() methods.
* battery: provider specific sensors for HA
* move Battery MQTT loop to BatteryStats
the BatteryStats class should handle the MQTT publishing, including the
interval. for the calculation of a reasonable Home Assistent expiration
value this class now also knows the maximum publish interval.
* JK BMS: fix publishing values for Home Assistent
Home Assistent values expire, because we set them to expire after three
MQTT publish durations. for that reason, we need to re-publish all
values after our self-inflicted full publish interval.
* define JK BMS sensors for Home Assistent
closes#482.
To reduce the heap usage it is necessary to send the inverters one by one instead of a huge response. A simple call to `/api/livedata/status` returns just some very general information. If detailed inverter information are required the inverter serial number has to appended `?inv=<serial number>`.
The websocket also returns only one inverter at a time. It as to be assembled at client side.
currently the whole SmartShunt data structure is copied to the
BatteryStats instance in every loop, even though the data cannot
possibly have changed. this is quite an expensive task to do in every
loop. this change tracks the last update timestamp and only does the
copy operation if an actual updated data structure was received from
the smart shunt.
OpenDTU console gets spammed with "WifiGeneric::hostByName() error when first trying to resolve the hostname via DNS. So reverse order: first try mDNS, if that fails try DNS. Also ensure that https bool is passed correctly to HTTPClient::begin(). Lastly, concatenate strings for building Digest authorization using "+" and not via snprintf.
this change utilizes some of the features from library "frozen", which
was included upstream for the grid profile parser. to improve code
maintainability, a couple of std::maps mapping strings to values or the
other way around were introduced in OpenDTU-OnBattery-specific code at
the expense of some flash and computing overhead.
library "frozen" offers constexpr versions of map and string, which
saves initialization code and offers slightly faster lookups. this
brings the binary size down by ~25kB and should provide a small
performance improvement at runtime.
Added ability to deal with local host names (mDNS), remove use of FirebasedJson to save ~20kB build size, some changes to PowerLimiter to avoid setting new inverter power limits when not needed (=current limit as reported by inverter is within hysteresis)
this battery provider implementation subscribes to a user-configurable
MQTT topic to retrieve the battery SoC value. the value is not
re-published under a different topic. there is no card created in the
web app's live view, since the SoC is already part of the totals at the
top of the live view. that is the only info this battery provider
implements.
closes#293.
relates to #581.