One winter weekend I went to my country house, and found out that it was very cold there. Something had happened with electricity and RCD breaker had switched it off, and the heating went off too. I was lucky I came there, otherwise in several days everything would had been frozen which is very bad for the pipes and the radiators.

I had several Raspberry Pi’s around, and a thermal sensor, so I thought — why don’t I make a simple monitoring device?

Instructions below assume you have a Raspberry Pi with Raspbian and network connection set up. In my case it is Raspberry Pi B+ with Raspbian (2018–06–27-raspbian-stretch-lite).

Temperature monitoring

How to connect a DS18B20 temperature sensor? Just google how to do this, and you’ll see a lot of pictures like this one:

In my case I had Black, Yellow and Red wires. The black is ground, goes to Ground pin, the red is power — goes to 3.3v pin, and the yellow is data — should go to GPIO4 pin, with 4.7 kOm resistor connected between data and power.

Note, you can connect several sensors in parallel (they are digital, and has different addresses), you need only one resistor.

After connecting your sensor, you should enable 1Wire in the raspi-config:

sudo raspi-config

Go to 5 Interfacing options, enable P7 1-Wire and reboot.

Then you can test if you can see the sensor:

sudo modprobe w1-gpio

sudo modprobe w1-therm

ls /sys/bus/w1/devices/

You should see something like this:

pi@vcontrol:~ $ ls /sys/bus/w1/devices/ 28–00044eae2dff w1_bus_master1

28–00044eae2dff is our temperature sensor.

Hardware is ready. Now I need to set up the monitoring part. I need something that would show me the data and notify me if the device is disconnected for a while or there is no power, or the temperature is low. Obviously this cannot be raspberry pi itself, there should be some server or service in the internet that monitors my device.

I can create a simple server, get a hosting and set everything up, but honesly, I don’t want to. Luckily, somebody has thought about this already and created cloud4rpi.io — a cloud control panel for your device.

Setting up Cloud4Rpi.io

Cloud4Rpi provides a service that let your device send and receive data using MQTT or HTTP protocols. They have a client library for Python, so I’ll use Python.

Python examples that comes with Cloud4Rpi service already contains code for DS18B20 temp sensor.

So i went to https://cloud4rpi.io, created an account and added a new device there. The device page has a token — a string that identifies the device, and which should be specified in the program that sends data.

To begin with, it is always a good idea to update a package manager and upgrade packages (note: it can take hours if you haven’t upgraded for a while):

sudo apt-get update && sudo apt-get upgrade

Then, install git, Python and its package manager Pip:

sudo apt-get install git python python-pip

Then, install cloud4rpi Python library:

sudo pip install cloud4rpi

Finally, i’m ready to write my control program. I start from example available at https://github.com/cloud4rpi/cloud4rpi-raspberrypi-python



cd cloud4rpi git clone https://github.com/cloud4rpi/cloud4rpi-raspberrypi-python.git cloud4rpicd cloud4rpi

The main program file is control.py — I need to modify it for my needs. First, edit the program and paste a token:

sudo nano control.py

Find a line DEVICE_TOKEN='...'] and specify a device token there. After that I can simply run the program:

sudo python control.py

It works and reports a temperature in RoomTemp variable:

Note that it discovers all onewire ds18b20 sensors ds_sensors = ds18b20.DS18B20.find_all() and uses the first found sensor:

'RoomTemp': {

'type': 'numeric',

'bind': ds_sensors[0] if ds_sensors else None

}

Ok, that was easy, because the sample program has everything that is requred to work with ds18b20 sensor on Raspberry Pi. Now I need to find the way to report the power status.

UPS monitoring

Next thing I want to monitor is UPS status, so if there is power outage, I will know about it before everything disconnects.

I have an APC UPS with USB control, so I quickly googled and found that I need apcupsd. http://www.anites.com/2013/09/monitoring-ups.html. I tried several times to install it via apt-get, and it was not working for me for various reasons. I’ll show how to install it from the sources.

wget https://sourceforge.net/projects/apcupsd/files/apcupsd%20-%20Stable/3.14.14/apcupsd-3.14.14.tar.gz tar xvf apcupsd-3.14.14.tar.gz cd apcupsd-3.14.14 ./configure --enable-usb sudo make sudo make install

Then I edit apcupsd.conf to connect to my UPS via usb.

sudo nano /etc/apcupsd/apcupsd.conf

#

#UPSCABLE smart

UPSCABLE usb

#

#UPSTYPE apcsmart

#DEVICE /dev/ttyS0

UPSTYPE usb

DEVICE

Now I can plug USB cable from UPS to RaspberryPi and test if UPS would be found.

sudo apctest

It should give you no error messages.

Now sevice apcupsd should be started:

sudo systemctl start apcupsd

To quiery UPS status I can use a status command:

sudo /etc/init.d/apcupsd status

And it would output somethig like this:

APC : 001,035,0855

DATE : 2018-10-14 16:55:30 +0300

HOSTNAME : vcontrol

VERSION : 3.14.14 (31 May 2016) debian

UPSNAME : vcontrol

CABLE : USB Cable

DRIVER : USB UPS Driver

UPSMODE : Stand Alone

STARTTIME: 2018-10-14 16:54:28 +0300

MODEL : Back-UPS XS 650CI

STATUS : ONLINE

LINEV : 238.0 Volts

LOADPCT : 0.0 Percent

BCHARGE : 100.0 Percent

TIMELEFT : 293.3 Minutes

MBATTCHG : 5 Percent

MINTIMEL : 3 Minutes

MAXTIME : 0 Seconds

SENSE : Medium

LOTRANS : 140.0 Volts

HITRANS : 300.0 Volts

ALARMDEL : 30 Seconds

BATTV : 14.2 Volts

LASTXFER : No transfers since turnon

NUMXFERS : 0

TONBATT : 0 Seconds

CUMONBATT: 0 Seconds

XOFFBATT : N/A

STATFLAG : 0x05000008

SERIALNO : 3B1424X02945

BATTDATE : 2014-06-10

NOMINV : 230 Volts

NOMBATTV : 12.0 Volts

NOMPOWER : 390 Watts

FIRMWARE : 892.R3 .I USB FW:R3

END APC : 2018-10-14 16:55:38 +0300

I need a status — which is the “STATUS:” line.

Cloud4rpi library contains a module ‘rpy.py’ that returns Raspberry Pi system parameters such as hostname or cpu temperature. Since all those params are results of running some commands and parsing output, it aslo contains a handy ‘parse_output’ function that does exactly what I need. This is how to get my UPS status:

def ups_status():

result = rpi.parse_output(r'STATUS\s+:\s+(\S+)', ['/etc/init.d/apcupsd', 'status'])

if result:

return result

else:

return 'UNKNOWN'

To send this status to cloud4rpi, i need to declare a variable UPSStatus and bind it to my ups_status function:

variables = {

'RoomTemp': {

'type': 'numeric',

'bind': ds_sensors[0]

},

'UPSStatus': {

'type': 'string',

'bind': ups_status

}

}

Now i can run my program:

sudo python control.py

And I can immediately see my variable at the cloud4rpi device page:

Preparing to “production”

Everyting is working, and now I need to prepare my device to unattended mode.

To begin with, i’m going to adjust time intervals. Poll interval defines how often the program checks for temperature and UPS status — i set it to one second.

Results are sent to the cloud every 5 minutes, and diagnostic information — every hour.

# Constants

DATA_SENDING_INTERVAL = 300 # sec

DIAG_SENDING_INTERVAL = 3600 # sec

POLL_INTERVAL = 1 # sec

When UPS status changes — i don’t want my device to wait for 5 minutes, and i send data immediately. So I have slightly modified the main loop and it looks like this:

data_timer = 0

diag_timer = 0

prevUPS = 'ONLINE' while True:

newUPS = ups_status()

if (data_timer <= 0) or (newUPS != prevUPS):

device.publish_data()

data_timer = DATA_SENDING_INTERVAL

prevUPS = newUPS if diag_timer <= 0:

device.publish_diag()

diag_timer = DIAG_SENDING_INTERVAL sleep(POLL_INTERVAL)

diag_timer -= POLL_INTERVAL

data_timer -= POLL_INTERVAL

Testing: run script:

sudo python control.py

And I can watch UPS status on my device page:

If I turn off UPS power, status changes in a couple of seconds, so everything is working.

Now I need to start apcupsd and my control.py on the system startup.

Apcupsd service is old and to start it on modern raspbian, I should modify /etc/init.d/apcupsd file, by adding these lines the somewhere at the top:

### BEGIN INIT INFO

# Provides: apcupsd

# Required-Start: $all

# Required-Stop:

# Default-Start: 2 3 4 5

# Default-Stop:

# Short-Description: APC UPS daemon…

### END INIT INFO#

Then enable the service:

sudo systemctl enable apcupsd

Then start the service:

sudo systemctl start apcupsd

Now apcupsd will be started on the system startup.

To install control.py as a service, I used the supplied service_install.sh script:

sudo bash service_install.sh ~/cloud4rpi/control.py

an now I can run control.py as a service:

sudo systemctl start cloud4rpi.service

Now service is started and it shouls survive a reboot.

Setting up a control panel

Cloud4rpi lets me set up a control panel for my device. You can add “widgets” and bind them to device variables.

My device provides two read-only variables — RoomTemp and UPSStatus:

variables = {

'RoomTemp': {

'type': 'numeric',

'bind': ds_sensors[0]

},

'UPSStatus': {

'type': 'string',

'bind': ups_status

}

}

I added 3 widgets — Number for RoomTemp, Text for UPSStatus and a Chart for RoomTemp:

I can set up alerts, so I receive an email when the temperature is out of specified range, UPS went offline or device itself does not send data when it should.

Now I can be sure my country house is ok, and I can be notified when something is wrong, so I can phone neighbours and ask them to check what is going on.

Here is the actual code of the control.py: