Measuring analog values on a Raspberry Pi without ADC

Contrary to the ESP8266 or the Arduino, the Raspberry Pi has no analog ports. In order to measure analog values, you can add an ADC. These usually are driven by the I2C port or by SPI.

If however  you only need to measure one analog value with a variable resistor sensor, there is a quick and easy way to do that without adding an ADC converter on your I2C. But, it will still cost you two pins.

If you take a look at the picture, the working appears pretty simple:
The Charge pin, when made HIGH starts charging the 100nF capacitor through the NTC. When at a certain time the voltage over the 100nF capacitor is high enough to be seen as a HIGH by the Raspberry, the ‘measure pin’ gets set from LOW (in fact from Zero) to HIGH. The time it takes from the start of the charge till the measure pin goes to HIGH is then a time value that is a measure for the value of the NTC. It is only influenced by the  value of the NTC. When we feed a Raspberry with 3.3 Volt, a HIGH on a pin means a minimum of 1.6 Volt, so in fact we are measuring the time it takes to charge a capacitor from zero to 1.6 Volt. The 1k resistor is just a safety precaution to prevent too much current coming from the capacitor when it is discharged.

It is paramount that the measurement is always taken from the same starting position, meaning an empty capacitor. The measurement procedure thus looks like this:

Empty capacitor
Start charging capacitor
Start timer
Wait till capacitor is HIGH
Read timer

to decharge the capacitor we can use the measuring pin.

Fortunately very often someone already has written a code that can be used and in this case it was SimonMonk

import RPi.GPIO as GPIO
import time

# declare GPIO mode
GPIO.setmode(GPIO.BCM)

# define GPIO pins with variables charge_pin and measure_pin
# 18=chargepin 23=measure
charge_pin=18 
measure_pin = 

# discharge the capacitor
def discharge():
    GPIO.setup(charge_pin, GPIO.IN) #stop charging
    GPIO.setup(measure_pin, GPIO.OUT) #make the measure pin an output
    GPIO.output(measure_pin, False) # set it low to discharge the capacitor
    time.sleep(0.005)

def charge_time():
    GPIO.setup(measure_pin, GPIO.IN) 
    GPIO.setup(charge_pin, GPIO.OUT)
    count = 0
    GPIO.output(charge_pin, True) #start charging the capacitor
    while not GPIO.input(measure_pin): #wait till the pin goes HIGH
        count = count +1
    return count

def analog_read():
    discharge()
    return charge_time()

# loop to display analog data count
while True:
    print(analog_read())
    time.sleep(1)
    


                  
Advertisement

Reading the DHT11 or DHT22 on the Raspberry via an overlay and send it to the openHab REST API

In an earlier tutorial I showed how to read the popular DHTxx sensor on a Raspberry Pi and then to MQTT that into Openhab.
However, there are more ways to skin a cat, so what I like to do this time is:

1) Read the sensor with a device tree overlay on a Raspi and then
2) Send the data to OpenHab with the REST-API

I am not saying one method is better than the other, but suppose you dont want to install an MQTT server because all your other channels don’t need MQTT, then the REST API comes in handy.

1) Reading the DHT sensor
First we need to load the dht11 overlay at boot-up
Do
sudo nano /boot/config.txt
and add:

dtoverlay=dht11,gpiopin=4

obviously one can pick another pin here, or declare a different sensor such as the DHT22 or DHT21 (AM2301)

then all you have to do is to read the following 2 files:

/sys/devices/platform/dht11@0/iio:device0/in_temp_input
/sys/devices/platform/dht11@0/iio:device0/in_humidityrelative_input

Once you have loaded the overlay and connected your sensor, a simple:
cat /sys/devices/platform/dht11@0/iio:device0/in_temp_input,
would show you the temperature.
whereas:
cat /sys/devices/platform/dht11@0/iio:device0/in_humidityrelative_input, would show you the humidity

Upon doing that in a python program, I noticed there can be quite a number of I/O errors. This seems to be a frequent problem with this overlay, so in order not to interrupt the program, I had to do a bit of Error catching.

2) Sending values to OpenHab
The REST API is fairly simple to use. We only need 1 line for every Item we want to update. Such a line looks like this:
requests.put('http://192.168.xxx.yyy:800/rest/items/<YOUR ITEM>/state',value).
The ‘value’-variable needs to be a string.

3) Wrapping it up
A simple Python program would look like so:

import time
import requests
tfile='/sys/devices/platform/dht11@0/iio:device0/in_temp_input'
hfile='/sys/devices/platform/dht11@0/iio:device0/in_humidityrelative_input'

def read_temp_raw():
   f=open(tfile,'r')
   lines=float(f.read())/1000.0
   f.close()
   return lines

def read_humidity_raw():
   b=open(hfile,'r')
   hlines=float(b.read())/1000
   b.close()
   return hlines

while True:
   try:
     T=str(read_temp_raw())
     print(T)
     H=str(read_humidity_raw())
     print(H)
     time.sleep(2)
     #Put your own IP and Itemnames here,
     requests.put('http://192.168.1.103:8080/rest/items/<ITEMNAME>/state',T)
     requests.put('http://192.168.1.103:8080/rest/items/<ITEMNAME>/state',H)

   except IOError:
      print("I/O error")

Beware that Python programs rely on proper indenting. As this sometimes can be corrupted by publication on a website, I will leave an image of the properly indented program below:

As I am not the world’ s best python coder, I am sure improvements can be made, but at least this code will get you up and running fast.
Since the OpenHAB items are updated through the REST API, they do not need a channel in the itemsfile, that could look as simple as this:

Number HH "REST Humidity [%.0f %%]" <humidity> (Weather)
Number HT "REST temperature [%.1f °C]" <temperature> (Weather)

Boot problems after mounting a USB stick on a Raspberry Pi Zero

This will just be a short piece, more like a tip to take into consideration.
While playing around with a Raspberry Pi Zero W, I had inserted  a USB OTG ‘hub’  that could take a micro SD card and a USB stick and I had mounted the medium that was in there.
My goal was to use the USB stick to write picture files from a security camera to, in order to spare the SD card.
As also my ordered headers arrived, I shut down the Raspberry, soldered the headers and started up again.
To my horror, it wouldn’t start. Fearing that my soldering somehow had damaged the raspberry Pi, I exchanged cards with a Raspberry Pi B and restarted both. Thank god, the ‘start problem’  was related to the card, not the raspberry.
But how was that possible. It was a new card, and I always had properly shut down the raspberry it was in.
Then it dawned on me, could it be… no it couldn’t, could it??
I realised that after soldering, I had not reinserted the OTG hub with USB stick anymore. Could that be the problem??
After re-inserting the OTG hub with USB stick, my Zero started immediately again.
Obviously that is not the behaviour I want. I will see if I can do something about it, but for now I removed the mount.

 

Controlling a GPIO pin on a remote raspberry

In an earlier post I showed how one could address the raspberry GPIO pins from within OpenHab (or NodeRed for that matter). The only limitation here was that it was on a raspberry that also hosted OpenHAB.

What if you have a RaspberryPi whose pins you want to control from within OpenHab, while openHab is in fact operating from another machine?

In that case  MQTT seems the best option. I wrote a Python program that will do just that.
If you installed Jessie or Stretch, it comes already with Python 2.7 which is quite suitable for this goal.
You will need two libraries:

The lightweight MQTT client Eclipse Paho Mqtt: Here I describe how to install it, but you could also just do:
pip install paho-mqtt

The second one you need to install is the Rpi.GPIO library.
LadyAda gives a good explanation  how to do that, but it basically comes down to issuing the command:
sudo apt-get install python-dev python-rpi.gpio

The Python program itself is fairly simple, but there are a few things to point out
The Rpi.GPIO library has two modes to set up the pins. it has ‘BCM mode’ and ‘BOARD mode’
These two modes refer to the numbering of the pin.

The GPIO.BOARD option specifies that you are referring to the pins by the number of the pin in the plug – i.e the numbers printed on the board.

The GPIO.BCM option means that you are referring to the pins by the “Broadcom SOC channel” number, these are the numbers after “GPIO” that can be seen in the various pinout diagrams

If you are still a bit puzzled, you can try and issue “the gpio readall” command on your terminal and depending on the type of Raspberry you have, you may get outputs like this for the Rpi3:

or this one for the B+
You will also need to set the IP for your particular MQTT broker and need to change the topic according to your wishes.

The program currently switches one pin ON or OFF. it is not particularly hard to expand that for more than one pin. The working can be controlled by the gpio readall command (check in the column ‘V’ what the state of the pin is)

I saved the program in my home/pi directory. It can be started by
python mqttpublish2.py (or any other name you want to give it). It is best to have it start at boot-up
Output will look like this:
A slight word of warning: Python sees indents as part of the command structure. If after downloading my file you go change it, be careful not to mess up the indents.
Edit: In the mean time I expanded the program a bit, it now sends the state of the pin as a seperate topic. It also sends the IP nr, the program name and an ‘alive’ message on startup. It uses pin 18.

 

OpenHab GPIO Example

I know this might not directly be Arduino or ESP8266 related, but I thought I’d publish it anyway as it may come in handy with openhab

First of all, install the GPIO binding in the PaperUI. After one has done that, there isnt really much else to do on that binding. There is no services/gpio.cfg although some of the documentation mentions that file.

Before I go further it is good to note that I used the openhabian distro and I presume a lot of things are already OK in that, but if you did a manual install, it might be good to check if the user ‘openhab’ is member of ‘gpio’ and if not, set that with

sudo adduser openhab gpio

That’s basically all one needs to do.
Let’s setup an ‘input’ which in openhab is a ‘Contact’ and an ‘output’, which in openhab is a Switch. In fact, those are the only states the binding allows.

There is no pressing need to define anything in your sitemap file if e.g. you add the items to a group in your itemsfile, but if you prefer a sitemap then add this to your sitemap file:

Switch item=GPIO_LAMP
Text item=GPIO_BUTTON

Let’s pick some pins to use. It is easiest to use pins on the Raspberry header that are close to a ground pin.

Looking at the pin out of the raspi, we see that for instance GPIO pins 21,13,5, 7, 10, 27,22,24,25,12,16,26, 3, 4, 8 and 17 are next to a ground pin, but some of those have reserved functions so i stayed away from those.
I picked GPIO23 and GPIO24 as that one is also close to a 3V3 pin and when using that as input one can always decide later to make that have a HIGH or a LOW input.The configuration string for the binding is defined as follows:

gpio="pin:PIN_NUMBER [debounce:DEBOUNCE_INTERVAL] [activelow:yes|no] [force:yes|no] [initialValue:high|low]"

for those who consider this as double dutch, it will become clear in the items definition:

Add this to your items file:

Switch GPIO_LAMP "Lamp" (LivingRoom) { gpio="pin:23 force:yes" }
Contact GPIO_BUTTON "Button [%s]" (LivingRoom) { gpio="pin:24 activelow:yes" }

The group ‘LivingRoom’ is not mandatory if you have defined your sitemap and of course you may use another group that suits you more.

The Switch that I set up is quite simple. In fact it already would be enough if it would have been:

Switch GPIO_LAMP "Lamp" {gpio="pin:23"}.

But with ‘force:yes’ we force the use of the pin even if it would have been in use by another process. Obviously that might not be the most elegant way to do it, but as i am pretty sure I am not using it for another process, I just wanted to make sure Openhab would have the pin available.

The current of a GPIO pin is far to small to drive any significant load as it can deliver some 60mA I think.
But the output can drive a small LED to test it… but use a 330 ohm series resistor, no matter what other websites tell you: you dont want to fry your GPIO pin. Eventually it would be more useful to drive a small relay module as long as it has a separate transistor to drive the relay (I know, I am cautious)

The configuration allows for some other parameters.
i already mentioned ‘force:yes|no

activelow yes|no  this means that when the switch is off, there is no voltage on the pin
initialValue:high:low determines the state the pin will take during initialisation.
debounce:interval is used to set the debounce value for the switch in milisecs

If we look at the output, I have not added an activelow because I thought that was the default value (but correct me if I am wrong)
If we look at our input, I set that to activelow, because the way the button works is it applies voltage to trigger the pin and I added it because I was not sure about the default
I did not set a debounce for the contact, but you could state:

Contact GPIO_BUTTON "Button [%s]" (LivingRoom) { gpio="pin:24 debounce:10 activelow:yes" }