Added heather algorithm

master
marcel 11 months ago
parent 439a6b6a1f
commit e99422412e
  1. 15
      CHANGELOG.md
  2. BIN
      build-doc/images/smart_heater.odg
  3. 1263
      build-doc/images/smart_heater.svg
  4. 13
      build-doc/images/wind_speed_diagram.svg
  5. 95
      build-doc/weather_station.html
  6. 61
      build-doc/weather_station.md
  7. BIN
      build-doc/weather_station.pdf
  8. 198
      firmware/weather_station.ino
  9. BIN
      test_software/__pycache__/epever_control.cpython-36.pyc
  10. 20
      test_software/epever_control.py
  11. 6
      test_software/weather_station_rs485_client.py

@ -26,3 +26,18 @@ All notable changes to this project will be documented in this file.
### Changed
- Heater of humidiy sensor only on when humidity is above 96% (was 80%). When heater is on temperature sensor also heats up, so use temperature sensor of BMP280 when heater is on.
## [0.2.1] - 2024-01-17
### Changed
- Heater algorithm updated. Idea from datasheet of humidity sensor from Temco Controls HUM-M2 humidity sensor module.
- ModBus read register 1: Scaled wind direction by 10 in order to also get the decimal position of the direction
### Added
- ModBus read register 12: Raw rain meter
- ModBus read register 13: Temperature from pressure sensor
- ModBus read register 14: Status bits
- ModBus coil register 0 : enable/disable heather algorithm

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 48 KiB

@ -9,9 +9,9 @@
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.2"
width="125.34mm"
height="165.31999mm"
viewBox="0 0 12534 16531.999"
width="60.926762mm"
height="80.360718mm"
viewBox="0 0 6092.6763 8036.0717"
preserveAspectRatio="xMidYMid"
fill-rule="evenodd"
stroke-width="28.222"
@ -45,7 +45,8 @@
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg439" />
inkscape:current-layer="svg439"
inkscape:document-rotation="0" />
<defs
class="ClipPathGroup"
id="defs8">
@ -347,7 +348,7 @@
</defs>
<g
id="g124"
transform="translate(-3234,-4235)">
transform="translate(-3234,-4234.9999)">
<g
id="id2"
class="Master_Slide">
@ -362,7 +363,7 @@
<g
class="SlideGroup"
id="g437"
transform="translate(-3234,-4235)">
transform="matrix(0.48609191,0,0,0.48609191,-1572.0212,-2058.5992)">
<g
id="g435">
<g

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

@ -564,7 +564,17 @@ But not before the temperature is measured and stored, as the sensor is
now cooled off to ambient temperature. If the humidity is below 95% the
sensor is free from moisture and the process is not repeated for another
hour.</p>
<p>Flow chart under development.</p>
<p>When the heater algorithm is active, the temperature is updated every
20 minutes instead of every 2 seconds. Statis bit 0 (ModBus register
30014) indicated if the heater is on or off and status bit 1 gives the
update rate of the main temperature sensor.</p>
<p>This algorithm can be enabled by setting the HeaterCoil (see ModBus
secion).</p>
<figure>
<img src="./images/smart_heater.svg" title="Heater algorithm"
alt="Heater algorithm" />
<figcaption aria-hidden="true">Heater algorithm</figcaption>
</figure>
<h2 id="temperature-1">Temperature</h2>
<p>The temperature is read from the humidity sensor as this sensor gives
the most accurate temperature readings. When the heater is on (see
@ -582,8 +592,8 @@ boring.</p>
now, the ModBus address is hard coded as 14 in the software. The values
are available in the input registers and can be read via function code
04.</p>
<p>Below an example of how to read the wind direction in Python using
the minimalmodbus library.</p>
<p>Below an example of how to read the wind direction and enable the
heater algorithm in Python using the minimalmodbus library.</p>
<pre><code>#!/usr/bin/env python3
import minimalmodbus
@ -592,10 +602,14 @@ instrument = minimalmodbus.Instrument(&#39;/dev/ttyUSB1&#39;, 14)
# register number, number of decimals, function code
wind_direction = instrument.read_register(1, 0, 4)
print(wind_direction)</code></pre>
<h3 id="input-registers">Input registers</h3>
<p>The measurements and order of the measurements are the same as for
APRS weather reports. But of course we use SI units.</p>
print(wind_direction)
# register address, value, function code
instrument.write_bit(0, 1, 5)</code></pre>
<h3 id="input-registers-read-only">Input registers (read only)</h3>
<p>Input registers are numbered 30001 to 39999 but have data addresses
0x000 to 0x270E. The measurements and order of the measurements are the
same as for APRS weather reports. But of course we use SI units.</p>
<table>
<colgroup>
<col style="width: 13%" />
@ -611,77 +625,77 @@ APRS weather reports. But of course we use SI units.</p>
</thead>
<tbody>
<tr class="odd">
<td>30000</td>
<td>00</td>
<td>Device ID (0x5758)</td>
<td>NO UNIT</td>
</tr>
<tr class="even">
<td>30001</td>
<td>01</td>
<td>Wind direction</td>
<td>degrees</td>
<td>degrees * 10</td>
</tr>
<tr class="odd">
<td>30002</td>
<td>02</td>
<td>Wind speed (average of 10 minutes)</td>
<td>m/s * 100</td>
</tr>
<tr class="even">
<td>30003</td>
<td>03</td>
<td>Wind gust (peak of last 10 minutes)</td>
<td>m/s * 100</td>
</tr>
<tr class="odd">
<td>30004</td>
<td>04</td>
<td>Temperature (two’s complement)</td>
<td>degrees Celcius * 100</td>
</tr>
<tr class="even">
<td>30005</td>
<td>05</td>
<td>Rain last hour</td>
<td>l/m2 * 100</td>
</tr>
<tr class="odd">
<td>30006</td>
<td>06</td>
<td>Rain last 24 hours</td>
<td>l/m2 * 100</td>
</tr>
<tr class="even">
<td>30007</td>
<td>07</td>
<td>Rain since midnight</td>
<td>NOT IMPLEMENTED</td>
</tr>
<tr class="odd">
<td>30008</td>
<td>08</td>
<td>Humidity</td>
<td>percent * 100</td>
</tr>
<tr class="even">
<td>30009</td>
<td>09</td>
<td>Barometric pressure</td>
<td>hPa * 10</td>
</tr>
<tr class="odd">
<td>30010</td>
<td>10</td>
<td>Luminosity</td>
<td>W/m2</td>
</tr>
<tr class="even">
<td>30011</td>
<td>11</td>
<td>Snow fall</td>
<td>NOT IMPLEMENTED</td>
</tr>
<tr class="odd">
<td>30012</td>
<td>12</td>
<td>Raw rain counter</td>
<td>NOT IMPLEMENTED</td>
<td>l/m2 * 100</td>
</tr>
<tr class="even">
<td>30013</td>
<td>13</td>
<td>Temperature (two’s complement)</td>
<td>degrees Celcius * 100</td>
</tr>
<tr class="odd">
<td>30014</td>
<td>14</td>
<td>Status bits</td>
<td>see table below</td>
</tr>
@ -705,12 +719,45 @@ from the pressure sensor.</p>
<td>heater off</td>
<td>heater on</td>
</tr>
<tr class="even">
<td>1</td>
<td>Temp update</td>
<td>every 2 sec</td>
<td>every 20 minutes</td>
</tr>
<tr class="odd">
<td>2</td>
<td>Heater algorithm</td>
<td>disabled</td>
<td>enabled</td>
</tr>
</tbody>
</table>
<p>The ModBus registers are 16 bit wide. For better precision, some
units are scaled by a factor of 10 or 100. This way, values with up to
two decimal points can be stored as 16 bit integer values. Just divide
by 10 or 100 to get the floating point values.</p>
<h3 id="output-coils-write-only">Output coils (write only)</h3>
<p>Input registers are numbered 1 to 9999 but have data addresses 0x000
to 0x270E. The default value is of a register is 0.</p>
<table>
<thead>
<tr class="header">
<th>Address</th>
<th>Description</th>
<th>logic 0</th>
<th>logic 1</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>0</td>
<td>Heater algorithm</td>
<td>disabled</td>
<td>enabled</td>
</tr>
</tbody>
</table>
<h1 id="schematic">Schematic</h1>
<p><a href="./images/weather_station_schematic.pdf"><img
src="./images/weather_station_schematic.svg" alt="Schematic" /></a></p>

@ -240,7 +240,11 @@ Via the I²C bus, the humidity value of the sensor is read. As the sensor can be
When the humidity rises above 95% for more than an hour the current temperature is stored and the heater is switched on for 10 minutes. Than the heater is switched off again. If after 10 minutes the humidity is still above 95% the heater is turned on again for another 10 minutes. But not before the temperature is measured and stored, as the sensor is now cooled off to ambient temperature. If the humidity is below 95% the sensor is free from moisture and the process is not repeated for another hour.
Flow chart under development.
When the heater algorithm is active, the temperature is updated every 20 minutes instead of every 2 seconds. Statis bit 0 (ModBus register 30014) indicated if the heater is on or off and status bit 1 gives the update rate of the main temperature sensor.
This algorithm can be enabled by setting the HeaterCoil (see ModBus secion).
![Heater algorithm](./images/smart_heater.svg "Heater algorithm")
## Temperature
@ -258,7 +262,7 @@ This sensor is still under development.
The weather station uses ModBus RTU over a simplex RS-485 line. For now, the ModBus address is hard coded as 14 in the software. The values are available in the input registers and can be read via function code 04.
Below an example of how to read the wind direction in Python using the minimalmodbus library.
Below an example of how to read the wind direction and enable the heater algorithm in Python using the minimalmodbus library.
#!/usr/bin/env python3
import minimalmodbus
@ -270,36 +274,49 @@ Below an example of how to read the wind direction in Python using the minimalmo
wind_direction = instrument.read_register(1, 0, 4)
print(wind_direction)
### Input registers
# register address, value, function code
instrument.write_bit(0, 1, 5)
### Input registers (read only)
The measurements and order of the measurements are the same as for APRS weather reports. But of course we use SI units.
Input registers are numbered 30001 to 39999 but have data addresses 0x000 to 0x270E. The measurements and order of the measurements are the same as for APRS weather reports. But of course we use SI units.
| Address | Description | Units |
|---------|-------------------------------------|-----------------------|
| 30000 | Device ID (0x5758) | NO UNIT |
| 30001 | Wind direction | degrees |
| 30002 | Wind speed (average of 10 minutes) | m/s * 100 |
| 30003 | Wind gust (peak of last 10 minutes) | m/s * 100 |
| 30004 | Temperature (two's complement) | degrees Celcius * 100 |
| 30005 | Rain last hour | l/m2 * 100 |
| 30006 | Rain last 24 hours | l/m2 * 100 |
| 30007 | Rain since midnight | NOT IMPLEMENTED |
| 30008 | Humidity | percent * 100 |
| 30009 | Barometric pressure | hPa * 10 |
| 30010 | Luminosity | W/m2 |
| 30011 | Snow fall | NOT IMPLEMENTED |
| 30012 | Raw rain counter | NOT IMPLEMENTED |
| 30013 | Temperature (two's complement) | degrees Celcius * 100 |
| 30014 | Status bits | see table below |
| 00 | Device ID (0x5758) | NO UNIT |
| 01 | Wind direction | degrees * 10 |
| 02 | Wind speed (average of 10 minutes) | m/s * 100 |
| 03 | Wind gust (peak of last 10 minutes) | m/s * 100 |
| 04 | Temperature (two's complement) | degrees Celcius * 100 |
| 05 | Rain last hour | l/m2 * 100 |
| 06 | Rain last 24 hours | l/m2 * 100 |
| 07 | Rain since midnight | NOT IMPLEMENTED |
| 08 | Humidity | percent * 100 |
| 09 | Barometric pressure | hPa * 10 |
| 10 | Luminosity | W/m2 |
| 11 | Snow fall | NOT IMPLEMENTED |
| 12 | Raw rain counter | l/m2 * 100 |
| 13 | Temperature (two's complement) | degrees Celcius * 100 |
| 14 | Status bits | see table below |
^NOTE^ Register 30013 holds the backup temperature reading from the pressure sensor.
| Status bits | Description | logic 0 | logic 1 |
|-------------|---------------|------------|-----------|
| 0 | Heater status | heater off | heater on |
| Status bits | Description | logic 0 | logic 1 |
|-------------|------------------|-------------|------------------|
| 0 | Heater status | heater off | heater on |
| 1 | Temp update | every 2 sec | every 20 minutes |
| 2 | Heater algorithm | disabled | enabled |
The ModBus registers are 16 bit wide. For better precision, some units are scaled by a factor of 10 or 100. This way, values with up to two decimal points can be stored as 16 bit integer values. Just divide by 10 or 100 to get the floating point values.
### Output coils (write only)
Input registers are numbered 1 to 9999 but have data addresses 0x000 to 0x270E. The default value is of a register is 0.
| Address | Description | logic 0 | logic 1 |
|---------|------------------|----------|---------|
| 0 | Heater algorithm | disabled | enabled |
# Schematic
[![Schematic](./images/weather_station_schematic.svg)](./images/weather_station_schematic.pdf)

Binary file not shown.

@ -67,9 +67,14 @@ const byte SlaveId = 14;
* 30004: Temperature (degrees Celcius)
* 30005: Rain last hour (l/m2)
* 30006: Rain last 24 hours (l/m2)
* 30007: Rain since midnight (l/m2)
* 30007: Rain since midnight (l/m2) [NOT IMPLEMENTED, always 0]
* 30008: Humidity (percent)
* 30009: Barometric pressure (hPa)
* 30010: Luminosity (W/m2)
* 30011: Snow fall [NOT IMPLEMENTED, always 0]
* 30012: Raw rainfall counter (mm)
* 30013: Temperature pressure sensor (degrees Celsius)
* 30014: Status bits 0=heater, 1-15: reserved
*
*/
const int SensorIDIreg = 0;
@ -82,6 +87,18 @@ const int SensorRainLast24Ireg = 6;
const int SensorRainSinceMidnightIreg = 7;
const int SensorHumidityIreg = 8;
const int SensorPressureIreg = 9;
const int SensorLuminosityIreg = 10;
const int SensorSnowFallIreg = 11;
const int SensorRainfallRawIreg = 12;
const int SensorTemperatureBackupIreg = 13;
const int SensorStatusBitsIreg = 14;
/* Modbus Registers Offsets (0-9999)
* Coils
* 0 = Heater algorithm (0 = disable, 1 = enable)
*/
const int HeaterCoil = 0;
// RS-485 serial port
#define MySerial Serial // define serial port used, Serial most of the time, or Serial1, Serial2 ... if available
const unsigned long Baudrate = 9600;
@ -116,68 +133,153 @@ struct MeasuredData {
int RainLast24;
int SensorRainSinceMidnight;
int Pressure;
int Luminosity;
int StatusBits = 0;
unsigned int RainfallCounter = 0;
float Temperature;
float Humidity;
float TemperatureBackup;
bool HeaterStatus = 0;
} MeasuredData;
// State machine implementing smart heater to prevent saturation of the sensor
char HeaterSi7021 (float humidity)
{
static int state=0;
static unsigned long StatemachineTimer=0;
bool TempValid=1;
bool Heater=0;
// If Smart heater algorithm is disabled, reset the statemachine forever.
// TempValid bit is also forced to 1, but it could be that we just came out of a heater period.
// We assume that the client on the other side of the ModBus is smart enough to understand.
if (MeasuredData.StatusBits & 0x04)
state = 0;
switch (state)
{
// Default state: humidity is below 95%
case 0:
Heater = 0;
if (humidity >= 95) {
StatemachineTimer = millis();
state = 1;
}
break;
// Humidity went above 95%. See if humidity stays above 95% for more than an hour, if so turn on heater
case 1:
if (humidity >= 95) {
if ( (millis() - StatemachineTimer) >= 3.6e+6 ) {
Heater = 1;
TempValid = 0;
StatemachineTimer = millis();
state = 2;
} else {
Heater = 0;
}
} else {
Heater = 0;
state = 0;
}
break;
// Heater is now on, let the sensor cook for 10 minutes
case 2:
if ( (millis() - StatemachineTimer) >= 600000 ) {
StatemachineTimer = millis();
Heater = 0;
state = 3;
} else {
Heater = 1;
}
TempValid = 0;
break;
// Heater is now off, let the sensor cool for 10 minutes
case 3:
if ( (millis() - StatemachineTimer) >= 600000 ) {
TempValid = 1; // Sensor cooled, so we can take a valid temperature reading
if (humidity >= 95) {
// Humidity still above 95%, repeat heating/cooling
Heater = 1;
StatemachineTimer = millis();
state = 2;
} else {
// Humidity below 95%, reset statemachine
Heater = 0;
state = 0;
}
} else {
Heater = 0;
TempValid = 0;
}
break;
default:
Heater = 0;
state = 0;
break;
}
return TempValid<<1 | Heater;
}
// Read Si7021 sensor and process data
void ReadSi7021 (void)
{
char result=0x2;
si7021.triggerMeasurement();
si7021.getHumidity(MeasuredData.Humidity);
si7021.getTemperature(MeasuredData.Temperature);
if (MeasuredData.Humidity>100 || MeasuredData.Humidity<0)
MeasuredData.Humidity = 100;
//If humidity is larger than 95% switch on heater to get more acurate measurement and prevent memory offset
result = HeaterSi7021(MeasuredData.Humidity);
MeasuredData.StatusBits &= 0xFFFC; // Reset heater status bits to zero
MeasuredData.StatusBits |= result; // And set the proper bits to one if there are any. The result is we copied the status bits to the register
// Scale for more decimal positions when converted to integer value for ModBus
MeasuredData.Humidity *= 100;
//If humidity is larger than 96% switch on heater to get more acurate measurement and prevent memory offset
//Switch off when lower than 94% (hysteresis)
if (MeasuredData.Humidity > 96 && !MeasuredData.HeaterStatus) {
Serial.print(F("Heater on."));
MeasuredData.HeaterStatus = 1;
si7021.setHeater(MeasuredData.HeaterStatus);
// Temperture readings are valid (as the sensor is not heated)
if (result & 0x2) {
si7021.getTemperature(MeasuredData.Temperature);
// Scale for more decimal positions when converted to integer value for ModBus
MeasuredData.Temperature *= 100;
//Serial.print(F("Valid temp"));
}
if (MeasuredData.Humidity < 94 && MeasuredData.HeaterStatus) {
Serial.print(F("Heater off."));
// Statemachine thinks it is time to switch on the heater
if (result & 0x1) {
//Serial.print(F("Heater on."));
MeasuredData.HeaterStatus = 1;
} else {
//Serial.print(F("Heater off."));
MeasuredData.HeaterStatus = 0;
si7021.setHeater(MeasuredData.HeaterStatus);
}
// Scale for more decimal positions when converted to integer value for ModBus
MeasuredData.Humidity *= 100;
MeasuredData.Temperature *= 100;
si7021.setHeater(MeasuredData.HeaterStatus);
}
// Read BMP280
void ReadBMP280 (void)
{
// MeasuredData.Pressure=0;
bmp280.awaitMeasurement();
float temperature;
bmp280.getTemperature(temperature);
float pascal;
bmp280.getPressure(pascal);
pascal = (pascal - PRESSURE_OFFSET) / 10; // Convert to hPa
MeasuredData.Pressure = pascal;
bmp280.getTemperature(MeasuredData.TemperatureBackup);
// Scale for more decimal positions when converted to integer value for ModBus
MeasuredData.TemperatureBackup *= 100;
bmp280.triggerMeasurement();
// When humidity is high, the heater of the Si7021 is on. This causes the temperature sensor of the humidity sensor to heat up.
// Use temperature sensor of BMP280 instead.
if (MeasuredData.HeaterStatus) {
bmp280.getTemperature(MeasuredData.Temperature);
// Scale for more decimal positions when converted to integer value for ModBus
MeasuredData.Temperature *= 100;
}
}
int MaxOfArray (int array[], unsigned int length)
@ -214,7 +316,8 @@ void ReadSparkfunWeatherStation (void)
float tmpRegister;
MeasuredData.WindDirection = weatherMeterKit.getWindDirection();
tmpRegister = 10*weatherMeterKit.getWindDirection(); // Use float for conversion to degrees times 10, than put it in integer register for ModBus
MeasuredData.WindDirection = tmpRegister;
tmpRegister = 100*(weatherMeterKit.getWindSpeed())/3.6; // Use float for conversion to m/s times 100, than put it in integer register for ModBus
MeasuredData.WindSpeed = tmpRegister;
tmpRegister = 100*weatherMeterKit.getTotalRainfall(); // Use float for conversion to l/m2 times 100, than put it in integer register for ModBus
@ -279,6 +382,9 @@ void ReadSparkfunWeatherStation (void)
RainPerHourCounter=0;
}
RainPerHour[RainPerHourCounter] = MeasuredData.Rain;
// Every time before we reset the TotalRainCounter we add the amount to the RawRainCounter.
// This 16 bit register will eventually overflow, but 655.35mm of rain fall is a lot!
MeasuredData.RainfallCounter += MeasuredData.Rain; // We don't care about the rounding error due to the convertion from float to int
weatherMeterKit.resetTotalRainfall();
// Calculate rain fall in the last 24 hours
@ -320,13 +426,22 @@ void setup() {
mb.addIreg (SensorRainSinceMidnightIreg);
mb.addIreg (SensorHumidityIreg);
mb.addIreg (SensorPressureIreg);
mb.addIreg (SensorLuminosityIreg);
mb.addIreg (SensorSnowFallIreg);
mb.addIreg (SensorRainfallRawIreg);
mb.addIreg (SensorTemperatureBackupIreg);
mb.addIreg (SensorStatusBitsIreg);
// Add HeaterCoil register
mb.addCoil (HeaterCoil);
// Set Weather station ID
mb.Ireg (SensorIDIreg, 0x5758);
// Set unused register to zero
mb.Ireg (SensorRainSinceMidnightIreg, 0);
mb.Ireg (SensorSnowFallIreg, 0);
Serial.println(F("Weather station v0.1.0"));
Serial.println(F("Weather station v0.2.1"));
Serial.println(F("(C)2024 M.T. Konstapel"));
Serial.println(F("This project is free and open source"));
Serial.println(F("More details: https://meezenest.nl/mees/"));
@ -346,6 +461,14 @@ void setup() {
}
}
// The standard library of the Si7021 sets the heater element to the default 3.1mA, but we want the full power
// We could alter the library, but than we break compatibility. So for this one time we do a raw-write to the
// heater register.
const uint8_t SI7021_I2C_ADDRESS =(0x40);
const uint8_t SI7021_CMD_WRITE_HEATER_CONTROL_REG =(0x51);
const uint8_t SI7021_HEATER_FULL_BLAST =(0x0F); // Set heater to 94mA
i2c.writeByte(SI7021_I2C_ADDRESS, SI7021_CMD_WRITE_HEATER_CONTROL_REG, SI7021_HEATER_FULL_BLAST);
// Initialize BMP280 pressure sensor
Serial.print(F("Pressure sensor BMP280 "));
if (bmp280.initialize())
@ -467,11 +590,22 @@ void loop() {
mb.Ireg (SensorTemperatureIreg, MeasuredData.Temperature);
mb.Ireg (SensorHumidityIreg, MeasuredData.Humidity);
mb.Ireg (SensorPressureIreg, MeasuredData.Pressure);
mb.Ireg (SensorTemperatureBackupIreg, MeasuredData.TemperatureBackup);
mb.Ireg (SensorLuminosityIreg, MeasuredData.Luminosity);
mb.Ireg (SensorRainfallRawIreg, MeasuredData.RainfallCounter);
mb.Ireg (SensorStatusBitsIreg, MeasuredData.StatusBits);
// Debug wind vane
//Serial.print(F("\n Measured ADC: "));
//Serial.print(analogRead(windDirectionPin));
// enable or disable smart heater
if (mb.Coil (HeaterCoil)) {
MeasuredData.StatusBits |= 0x04; // Set bit
} else {
MeasuredData.StatusBits &= 0x0B; // Reset bit
}
digitalWrite(LED_BUILTIN, LOW); // LED as heartbeat

@ -52,6 +52,10 @@ class EpeverChargeController(minimalmodbus.Instrument):
@retry(wait_fixed=200, stop_max_attempt_number=5)
def retriable_read_bit(self, registeraddress, functioncode):
return self.read_bit(registeraddress, functioncode)
@retry(wait_fixed=200, stop_max_attempt_number=5)
def retriable_write_bit(self, registeraddress, data, functioncode):
return self.write_bit(registeraddress, data, functioncode)
#Address range 0x3000
def get_id(self):
@ -60,7 +64,7 @@ class EpeverChargeController(minimalmodbus.Instrument):
def get_wind_direction(self):
"""PV array rated current"""
return self.retriable_read_register(1, 0, 4)
return self.retriable_read_register(1, 1, 4)
def get_wind_speedl(self):
"""PV array rated power (low 16 bits)"""
@ -93,3 +97,17 @@ class EpeverChargeController(minimalmodbus.Instrument):
def get_pressure(self):
"""Charging mode: 0x0001 = PWM"""
return self.retriable_read_register(9, 1, 4)
def get_temperature_backup(self):
"""Charging mode: 0x0001 = PWM"""
return self.retriable_read_register(13, 2, 4)
def get_status_bits(self):
"""Charging mode: 0x0001 = PWM"""
return self.retriable_read_register(14, 0, 4)
def enable_heater(self):
self.retriable_write_bit(0, 1, 5)
def disable_heater(self):
self.retriable_write_bit(0, 0, 5)

@ -594,7 +594,9 @@ elif dump_file:
dump_all_registers()
else:
status = 1
print("Enable heater function")
controller.enable_heater()
while (1):
time.sleep(3) # Sleep for 3 seconds
print ("Retrieving all known registers.")
@ -608,6 +610,8 @@ else:
rawdat['Temperature'] = controller.get_temperature()
rawdat['Humidity'] = controller.get_humidity()
rawdat['Pressure'] = controller.get_pressure()
rawdat['Temp backup'] = controller.get_temperature_backup()
rawdat['Status bits'] = controller.get_status_bits()
print (json.dumps(rawdat, indent=1, sort_keys=False))

Loading…
Cancel
Save