Project Curacao – The Software System
Note: Project Curacao has been upgraded to use the SunAirPlus Boards. Addresses and software updated on March 23, 2015 to use the INA3221 in the SunAirPlus board.
System description
Project Curacao consists of four subsystems. A Raspberry Pi Model A is the brains and the overall controller. The Power subsystem was described in part 1, the Environmental Sensor subsystem was described in part 2 and the Camera subsystem was shown in part 3. This article goes through the software architecture of the system.
There are two computers in Project Curacao. The main “brains” of the project reside in the Raspberry Pi in a program called ProjectCuracaoMain. The ProjectCuracaoMain program contains approximately 5000 lines of code in Python. The BatteryWatchdog Arduino has 3000 lines of code written in C/C++. The third program, RasPiConnect, contains 3000 lines of code (counting only Local.py – the customized code) and is used for display, control and remote access from an iPhone or iPad.
Architecture of the Python code
The ProjectCuracaoMain Python file is not complex. It consists of some setup code and then the initialisation of the Python package apscheduler with the various programs to be run periodically. The scheduling code is very simple and is shown below.
scheduler = Scheduler()
job = scheduler.add_cron_job(powerdatacollect.datacollect5minutes, minute=”*/5″, args=[‘main’, 0])
job = scheduler.add_cron_job(watchdogdatacollect.watchdogdatacollect, minute=”*/5″, args=[‘main’, 10])
job = scheduler.add_cron_job(environdatacollect.environdatacollect, minute=”*/15″, args=[‘main’, 70])
job = scheduler.add_cron_job(systemstatistics.systemstatistics15minutes, minute=”*/15″, args=[‘main’,40])
job = scheduler.add_cron_job(doallgraphs.doallgraphs, minute=”*/15″, args=[‘main’,10,100])
# camera
job = scheduler.add_cron_job(useCamera.takeSinglePicture, hour=”*”, args=[‘main’,50])
# send daily picture
job = scheduler.add_cron_job(sendPictureEmail.sendPictureEmail, hour=”22″,minute=”20″, args=[‘main’,0])
sys.stdout.write(‘Press Ctrl+C to exit\n’)
scheduler.start()
The key concept of the above code is that each of the jobs is fired off in its own thread and not in the main thread of ProjectCuracaoMain. What is the advantage of this? If the thread code bombs then just the thread code stops running, leaving the main program and other threads intact.
Project Curacao Architecture |
You can also run more than one thing at a time, but we minimise that to avoid the load on the Raspberry Pi. The apscheduler Python package, detailed at https://pythonhosted.org/APScheduler, generates the threads for you, so it is very easy to use.
We communicate between threads through files in the “state” directory. One improvement we will be making in the thread code is to put in a lock for the BatteryWatchdog serial port to keep threads from stepping on each other when sending and receiving serial data out to the BatteryWatchdog. New to threading? An excellent tutorial is at https://www.tutorialspoint.com/python/python_multithreading.htm.
Each of the threads are simple pieces of code that actuate hardware, send email, build graphs, collect data and write to the MySQL database.
The remainder of the main program code is for setup and handling interrupts.
Doing hard time
The main software (and the BatteryWatchdog) is a realtime system. It is characterized as a “soft” realtime system because it is not guaranteed that a particular task will run at the exact time requested. Other system tasks may interrupt the software. Tasks can even be lost. This is fine for this system, but you don’t want your car braking system to operate that way. “Hard” realtime systems are designed to ensure that all tasks are executed when required.
Watchdog timer
Anyone who has written complex code knows that there are still bugs remaining in the software which could prevent the software from functioning. It is also true that the Raspberry Pi OS sometimes hangs and there is always the danger of a voltage spike, lightning bolt or something causing the Raspberry Pi to stop responding. We combat this with a watchdog timer implemented with an Arduino to reboot the Raspberry Pi periodically and also when there is an issue. The Raspberry Pi sends an “I am still here” to the BatteryWatchdog every five minutes (in the sendWatchDogTimer.py program under the housekeeping directory).
If the BatteryWatchdog doesn’t receive these messages for 15 minutes, then it sends an interrupt to the Raspberry Pi and tells it to shutdown (always a good idea if possible). The BatteryWatchdog waits for 5 minutes and then power cycles the Raspberry Pi. Then you have the question of “Who watches the watchdog?”. This is partially answered by the use of a deadman switch in the BatteryWatchdog software, which was detailed last month. A better solution would be to implement a hardware timer that would reboot the BatteryWatchdog if it goes away.
Crontab entry
Crontab is a utility on the Pi that will periodically call a program or a command. We only use crontab for one thing in Project Curacao and that is to send the graphs and current photograph to a webpage hosted by our good friends at MiloCreek (developer of RasPiConnect). You can see them at https://milocreek.com/projectcuracaographs.
Architecture of the BatteryWatchdog
Arduino Architecture |
The BatteryWatchdog is built on a state machine model. We have two main states in the system. State0 contains housekeeping code, the timed alarms and the watchdog code. State0 is the “normal” run state of the system.
When an interrupt is received from the Raspberry Pi the software transitions to State1, where the serial data from the Raspberry Pi is dealt with and data is sent to the Raspberry Pi. This is a classic software state machine design.
}
Note that we did not use the timed alarm Arduino library as it doesn’t work if you put the Arduino to sleep (to save current). We also used an average reading technique to reduce the noise and issues in the Arduino built-in analogue-to-digital converters.
Total sensor count
We have 11 I2C devices in Project Curacao. We also use 14 GPIO pins and a total of 5 A/D pins. The table is below.
RaspBerry Pi i2c Mappings
i2c address | Device | Function |
---|---|---|
0x29 | BM017 / TCS34725 | RGBC Color Sensor |
0x39 | TSL2561 | Luminosity Sensor |
0x40 | INA3221 | Raspberry Pi Input Voltage/Current on SunAirPlus Board |
0x48 | ADS1015 A/D | 12 bit A/D converter on SunAirPlus Board |
Channel 0 | Pi Battery Temperature | |
Channel 1 | Camera Servo Feedback Potentiometer | |
0x77 | BMP085 | Baro/Temp readings |
RaspBerry Pi GPIO Mappings (GPIO.setmode(GPIO.board))
RPI.GPIO | Raspberry Pi Name | BCM2835 | Pin Number | Function |
---|---|---|---|---|
7 | GPIO7 | GPIO4 | P1_07 | Rising Edge Interrupt to Arduino |
8 | TXD | GPIO14 | P1_08 | TXD to Arduino |
10 | RXD | GPIO15 | P1_10 | RXD to Arduino |
12 | GPIO1 | GPIO18 | P1_12 | Software PWM for Camera Servo |
15 | GPIO3 | GPIO22 | P1_15 | Pulse to Turn Fan Off |
16 | GPIO4 | GPIO23 | P1_16 | DHT22 Temp/Hum Interface |
18 | GPIO5 | GPIO24 | P1_18 | Pulse to Turn Fan On |
22 | GPIO6 | GPIO25 | P1_22 | Activity LED |
Arduino Battery Watchdog i2c Mappings
i2c address | Device | Function |
---|---|---|
0x40 | INA3221 | Arduino Input Voltage/Current on SunAirPlus Board |
0x48 | ADS1015 | ADC ADS1015 on SunAirPlus Board |
0x5C | AMS 2315 | Outside Temp/Humidity |
0x68 | DS3231 | Real Time Clock |
Arduino Battery Watchdog GPIO Mappings
GPIO | Function | Comments |
---|---|---|
22 | Interrupt Pi | Level |
27 | Pi Latched Relay Reset | Pulse |
29 | Pi Latched Relay Set | Pulse |
35 | LED Pi Interrupt On | Arduino Battery Voltage/Current |
41 | Select Wind Set | Wind Turbine |
43 | Select Solar Reset | Solar Panels |
Arduino Battery Watchdog A/D Mappings
Channel | Function |
---|---|
A3 | Pi Battery Voltage |
A5 | Regulated Wind Voltage |
A7 | Unregulated Wind Voltage |
A9 | Pi Solar Voltage |
RasPiConnect code
The RasPiConnect app can be obtained from https://www.milocreek.com. All the code is located in the Local.py file available on GitHub https://github.com/projectcuracao/RasPiConnectServer. It involves a total of 93 controls and a number of graphs. We use it on a regular basis to monitor the project.
Remote access to the system
Remote access to the system is achieved with SSH and by HTTPS via RasPiConnect. Since these ports are exposed to the internet both are password protected with 12 letter random passwords. A rule to remember is ANYTIME you expose a port to the internet, you need to use complex difficult passwords. We use https://identitysafe.norton.com/password-generator to generate these.
All of the code used in this article is posted on GitHub at https://github.com/projectcuracao.
I now see that you use SSH and HTTPS to connect to you Pi. I can’t because my provider does not allow me to run it as a server. I mainly use HTTPS and SCP to send data from the Pi to my server that runs the interface. This is also why I had to implement sending shell commands by email.
Sorry for troubling, still like to follow your project.
Cheers, Paul