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.  

void loop() {
  // state machine
  printStateVariables();
 
  switch (currentState)
  {
     case  STATE0:
       nextState = state0(currentState);
     break;
    
     case STATE1:
        nextState = state1(currentState);
     break;
     
     default: 
     break;
  }
  checkForAlarms();
 
  if (nextState == currentState)
  {
    // sleep
    delay(1000);
    sleep.pwrDownMode();
    sleep.sleepDelay(sleepTime); 
  }
  currentState = nextState;

}


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.

1 Comment

  1. 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

1 Trackback / Pingback

  1. Tutorial: Part 11 -Building a Solar Powered Raspberry Pi Weather Station - GroveWeatherPi - SwitchDoc Labs

Leave a Reply

Your email address will not be published.


*