rasProject_01 / weSweetHome
R. 240
process control / RasPi software by weinert-automation
|
Process control for a slightly smart home. More...
#include "arch/config.h"
#include "sweetHome2.h"
#include "weUtil.h"
#include "weModbus.h"
#include "weStateM.h"
#include "weLockWatch.h"
#include "weEcarLd.h"
#include "weShareMem.h"
#include "weAR_N4105.h"
#include <errno.h>
#include <sys/sem.h>
#include <getopt.h>
#include "sweetHomeLocal.h"
Functions | |
void | batCntBalStatChg (state_t *const me) |
Battery as controlled ballast SFC state changes. More... | |
void | batCntLodStatChg (state_t *const me) |
Battery controlled load or keep; SFC state changes. More... | |
void | batUnloadStatChg (state_t *const me) |
Battery unload SFC state changes. More... | |
void | hotWatPmpCntlTimChg (state_t *const me) |
Hot water comfort pump control timer state change function. More... | |
void | hotWatPmpSchTimChg (state_t *const me) |
Hot water comfort pump schedule timer state change function. More... | |
void | hotWpmpButChg (state_t *const me) |
Hot water comfort pump button state change. More... | |
void | initDawnDusk () |
Adjust dawn and dusk timers. More... | |
void | initSunRiSet (int init) |
Initialise dawn, sunrise, sunset and dusk timers. More... | |
void | load250WstateChg (state_t *const me) |
Controlled fixed surplus consumption; SFC state changes. More... | |
int | main (int argc, char **argv) |
The program. More... | |
void * | processIOthread (void *args) |
The task of controlling process IO. More... | |
int | readRetFil (void) |
Read (day start) retain file. More... | |
void | switchARN4105 (uint8_t const cutOff) |
AR-N 4105 implementation function. More... | |
int | writeRetFil (void) |
Write (day start) retain file. More... | |
Variables | |
state_t | batCntBalSeq |
Battery controlled load as ballast. | |
state_t | batCntLodSeq |
Battery loading and keeping. | |
state_t | batUnloadSeq |
Battery controlled unload via inverter. | |
__time_t const | hotTimSched [] |
Schedule times for hot water comfort pump starts. More... | |
state_t | hotWatPmpCntlTimer |
Hot water comfort pump control timer. More... | |
state_t | hotWatPmpSchTimer |
Hot water comfort pump schedule timer. More... | |
state_t | load250Wcont |
Controlled load SFC. | |
char const | prgNamPure [] |
The pure program name. More... | |
char const | prgSVNdat [] |
The complete SVN date string. More... | |
char const | prgSVNrev [] |
The complete SVN revision string. More... | |
Process control for a slightly smart home.
The program's tasks are mainly related to electrical power involving two or three smart meters (three phase 230/400V) and power modules for battery and solar panel / inverter handling. 2017 the development started on a realistic laboratory experiment and soon (mid 2018) spun off to a real life home control set-up with extra comfort and buffer battery functions.
The MQTT topic root "labExp/sweetHome/" as well as the "hometers" in the application were kept so far out of reverence for the very beginnings.
The program runs on a Raspberry with GUI-less (no graphics) Raspbian lite having an Apache Webserver and a MQTT broker on the same machine. GUI/HMI is featured as Web-Interface (Apache, C CGI) on the (W)LAN.
Revision history
Communication
This program uses serial half duplex communication with a TTL to RS485 converter to handle smart meters (max. 10 m away) via Modbus. The RS485 module ("shield") forwards all GPIO pins covered. Growatt inverters have Modbus via RS232 (not sharable and lower range) and one of them got an extra ¶ęC to provide a MQTT interface; see growattLink.c.
MQTT protocol [W]LAN is used to attach more remote periphery, like a battery surveillance connected directly to and supplied by the battery clamps. Other MQTT periphery devices are of the shelf remote power relays. An extra Pi with Modbus over V.24 is supervising a Growatt inverter.
Examples for messages to parse: 'Up: 119.6V P: 65.0W L: 7.2W T: 26.5gdC Wd/t: 0.0 / 2316.2kWh' for topic 'labExp/sweetHome/grow01/meas' 'batU 0 : 12.19 V, adc:641' for topic 'labExp/sweetHome/bat/volt' '{"POWER":"ON"}' for topic 'labExp/sweetHome/plug01/RESULT' 'ON' for topic 'labExp/sweetHome/plug01/POWER' '{"POWER":"OFF"}' for topic 'labExp/sweetHome/plug01/RESULT' 'OFF' for topic 'labExp/sweetHome/plug01/POWER'
HTTP is used for GUI (via Apache). HTTPS is not used as all devices are in a guarded private home or laboratory network. Hence the Pi can't get a Let's Encrypt certificate and self signed ones aren't worth the while.
A 1-wire bus is used to add some analogue sensors to the ADC abstinent Raspberry. At present there are three hot water tank / pipe temperatures sensors to limit the 0..1kW ballast heater usage.
Common memory is used to communicate with other programs. At present this is a CGI program (meteRead.c) handling the AJAX link to the Apache based Web interface (meteRead.html).
GPIO usage
GPIO pins are used to control relays, LEDs and one button switch in the Pi's immediate neighbourhood. Three open drain outputs in a small extra module control slightly remote (10m) periphery via shielded cable and acts as guard to the virtually un-protected Raspberry IO pins.
The GPIO configuration definitions are found in file sweetHome2.h.
Modbus usage
This program acts as client for B+G E-Tech EASTRON smart meters. In the current (2017..23) configuration these are one SDM630-Modbus and one SDM530-Modbus three phase meter. (One phase meters like SDM230-Modbus were used in early experimental lab set-ups, only). Even in the Lab, no B+G E-Tech EASTRON Modbus communicated reliably above 9.6 baud (the default). Due to this low speed and, additionally, low response times, only two meter readings per second are possible over one RS485 line.
Communication will be 'RTU / RS485 9600, none' as common denominator. See Eastron, SMD230Modbus, Smart Meter Modbus Protocol Implementation V1.2 Eastron, SDM630Modbus, Smart Meter Modbus Protocol 630 (V1.5 ?) Eastron, SDM530Modbus, Smart Meter Modbus Protocol 530 (V1.1 or V1.5)
Due to the similar register layout, the meter types can be replaced with virtually no change in program. The SMD230, of course, can only be used if one phase (L1) is sufficient. Due to its technical inferiority it is not recommended except if space limitations on the DIN rails are hard.
This hometersControl application variant uses two three phase meters: A - slave 0: a SDM530Modbus three phase meter for the whole house. L1 L2 L3 are the three phases, each max. 80 A to supply the building under experiment. Import means power flows from public supply. Export is considered prohibited and will be inhibited by controlling suitable consumers, as water tank heater, and the buffer battery. In 2023 a car chargers power control/limit (by PWM) will be added. B - slave 3: a SDM630Modbus meter is used for two solar panel groups (A1/mJB, B3/big) and one for waste (ballast) and battery (C3/xLD). Import means power flow from panels respectively battery; export means battery charging and extra (waste/ballast) consumers including idle inverter losses.
Timing
The program has a cyclic process control (in SPS manner). As of Revision 150 we have
a) a 20 ms cycle for phase packet switching
b) a 100 ms cycle for process control, process I/O, SFCs etc.
c) an 1s cycle for Modbus *) communication, timer handling and some SFCs
The 100 ms cycle b) does not use the the library's (weUtil.c / .h) own generic 100 ms cycle but a by 5 sub-division of the 20 ms cycle a).
The generic cycles (a and c) are, by library implementation, own threads.
) The Eastron meter communication is dead slow by both answering delays and default baud rate. All experiment deviating from default settings failed.
Server functions
This program handles error, log, hibernation etc. files to provide values for humans and other programs.
Additionally shared memory and a set of three semaphores is provided to share current values with other (C) programs as well as for receiving command and status information. This interface is also used to provide web interfaces in a flexible way.
And the program acts as MQTT subscriber and publisher using a mosquitto broker, currently on the same Raspberry Pi. The primary MQTT purpose was to have "own" MQTT periphery. Those are remote power relays and a battery voltage monitoring ESP8266 in the private LAN – the latter due to Pi's lack of analogue input.
Library usage
The program uses the standard libraries pthread, pigpiod_if2, modbus, shm, sem and mosquitto. The own libraries in weRasp/..c and include/..h, namely weModbus, weGPIOd, sysUtil, weShareMem, weCGIajax etc. are compiled and linked in.
They could also be converted to and used as .so library. But, in the application environment given, this approach brings no advantage.
Build the program
cross-compile by:
program by:
or due to some bugs in make use winscp and IP directly by:
void initDawnDusk | ( | ) |
Adjust dawn and dusk timers.
This method initialises the settings of the dawn and dusk timers in the initialising process.
int readRetFil | ( | void | ) |
Read (day start) retain file.
int writeRetFil | ( | void | ) |
Write (day start) retain file.
void initSunRiSet | ( | int | init | ) |
Initialise dawn, sunrise, sunset and dusk timers.
The function is currently used only at program start start.
If the parameter init is true valFilVal .dayStrtVal values will be calculated for the current day. Otherwise the are assumed to be valid, i.e. read usually from that days start (hibernation) file. initDawnDusk() will be called in any case.
init | true: dayStrtVal else use |
void hotWatPmpCntlTimChg | ( | state_t *const | me | ) |
Hot water comfort pump control timer state change function.
It turns the pump on respectively off. At turning off the next on schedule is determined and set.
me | pointer to the pump timer |
void hotWpmpButChg | ( | state_t *const | me | ) |
Hot water comfort pump button state change.
This function (re-) triggers the hot water comfort pump timer.
void hotWatPmpSchTimChg | ( | state_t *const | me | ) |
Hot water comfort pump schedule timer state change function.
It starts pump control timer.
me | pointer to the pump timer |
void batUnloadStatChg | ( | state_t *const | me | ) |
Battery unload SFC state changes.
This sequential state machine organises the battery unload via a step up converter module and an inverter normally used for a small panel set. It handles all switching steps and (inhibit) conditions.
me | pointer to the battery unload SFC, never NULL |
void batCntBalStatChg | ( | state_t *const | me | ) |
Battery as controlled ballast SFC state changes.
This sequential state machine organises the battery load to be a ballast for surplus energy.
me | pointer to the battery unload SFC, never NULL |
void batCntLodStatChg | ( | state_t *const | me | ) |
Battery controlled load or keep; SFC state changes.
This sequential state machine organises the battery loading and keeping it in good load state. Not to be confused with batCntBalStatChg, i.e. using battery as storage/ballast.
me | pointer to the battery unload SFC, never NULL |
void load250WstateChg | ( | state_t *const | me | ) |
Controlled fixed surplus consumption; SFC state changes.
This sequential state machine organises the the handling of a load of about 250 W with restricted switching rules. One example is a compressor air drier.
The rules implemented here are:
When switched ON, run at least 30 minutes before allow turning OFF.
Do not turn ON twice within 2 hours.
Do not run longer than 4 hours.
The controlled load is at relay 5 (plug 10A at the electrical switch box) and Plg1 (MQTT).
me | pointer to the controlled load (0) SFC, never NULL |
void switchARN4105 | ( | uint8_t const | cutOff | ) |
AR-N 4105 implementation function.
This is the VDE-AR-N 4105 cut off function to be provided site specific by user / application software. It does the cut off respectively switch back on the generators and optionally log the event.
cutOff | not 0: do the cut off, 0: switch generators back on |
void * processIOthread | ( | void * | args | ) |
The task of controlling process IO.
With the exception of the Modbus / RS485 coupled smart meters, this thread controls almost all processIO: 8 relay outputs, some LEDs, one button input, one PWM signal and some open drain M-switches.
It is a 20 ms cycle thread to control line power by phase packet switching while all the rest is effectively done in a 100 ms cycle, i.e. every 5th 20ms cycle.
The cyclic 100 ms task then distinguishes 10 steps within a second and sometimes differentiates odd and even seconds by the actual Modbus slave number in the respective 1s RS4885 thread. This ten (0..9) respectively twenty steps serve the synchronisation with the other thread and act as state machine framework.
int main | ( | int | argc, |
char ** | argv | ||
) |
The program.
run by: hometersControl [options
For options see longOptions and :: optHlpTxt.
char const prgNamPure[] |
The pure program name.
To be provided in the application's / program's source.
char const prgSVNrev[] |
The complete SVN revision string.
To be provided in the application's / program's source.
char const prgSVNdat[] |
The complete SVN date string.
To be provided in the application's / program's source.
__time_t const hotTimSched[] |
Schedule times for hot water comfort pump starts.
This is a sorted array starting with the earliest start time in seconds relative to local midnight. At least the first (earliest) entry has to be put at the end 24h (86400s) later, to find a next day entry.
Hint: The first entry itself is nevertheless not dispensible as the program may be started between midnight and that time.
Hint 2: At days with DST change the first time in that day will be by one hour wrong. But beware using this approach for other purposes without consideration.
Hint 3: This sorted array of a day's clock readings might be replaced by an array of structures to implement day of week as filter condition for a schedule time.
state_t hotWatPmpSchTimer |
Hot water comfort pump schedule timer.
This timer is running to the next time to start the comfort pump on schedule. On running out it will trigger the pump control timer to start the pump or prolong its run time accordingly. Afterwards this timer will be restarted to the next schedule point in future.
state_t hotWatPmpCntlTimer |
Hot water comfort pump control timer.
This timer is running / active as long as the comfort pump is running. It might be triggered or prolonged by push button (hotWpmpButChg), web interface command or the pump schedule timer.