Problems with GPIO push button on self build emonPi

Ok, so try this for size

#!/usr/bin/python3

import glob
import time
import paho.mqtt.publish as publish

Broker = '127.0.0.1'
auth = {
    'username': 'emonpi',
    'password': 'emonpimqtt2016',
}

Sensors = {'SENSOR_A':'28-800000abc123',
           'SENSOR_B':'28-800000def456',
           'SENSOR_C':'28-800000abc456'}

def read_temp(sensorid):
    valid = False
    temp = 0
    device_file = '/sys/bus/w1/devices/' + sensorid + '/w1_slave'
    with open(device_file, 'r') as f:
        for line in f:
            if line.strip()[-3:] == 'YES':
                valid = True
            temp_pos = line.find(' t=')
            if temp_pos != -1:
                temp = float(line[temp_pos + 3:]) / 1000.0

    if valid:
        return temp
    else:
        return None


while True:
    for name, id in Sensors:
        temp = read_temp(id)
        if temp is not None:
            pub_topic = 'emon/Temperatures/' + name + '/values'
            publish.single(pub_topic, str(temp),
                    hostname=Broker, port=1883,
                    auth=auth,)
    time.sleep(6)

You will need to replace the “Sensors” details with your own sensor ids and chosen names. You can get the sensor ids by running ls -l /sys/bus/w1/devices from the command line.

If it works (still untested at my end) it should give you a single node called “Temperatures” and each sensor should appear by name under that node in emoncms.

I haven’t altered any of the temperature value conditioning etc, just added the list of sensors and edited what we had to loop through that list, read the temp by id and to publish to a topic by name. I assume the topic will work only because you had it working previously. Fingers crossed.

[edit - attached file - mqtt-temp.py.txt (1.1 KB)]

pi@emonpi:/usr/local/bin $ python mqtt-temp
Traceback (most recent call last):
  File "mqtt-temp", line 35, in <module>
    for name, id in Sensors:
ValueError: too many values to unpack
pi@emonpi:/usr/local/bin $ ```

I think I know what the issue is - I think the device_file string might contain a character that emoncms does not accept for a topic name. I had an issue with ‘:’ (issue #1105) and the symptoms were a new input generated every time. A colon should not affect it as the quick fix was merged. But this was never investigated for other characters.

To debug, you also need to monitor the MQTT broker from a different machine. You can get Windows MQTT clients to do that or use the ‘mosquitto_sub’ command from another Linux machine (or even a second SSH connection).

My bad, I was out later than expected last night so it was a bit rushed when I posted. Change line 35 to use Sensors.iteritems() rather than Sensors should fix that.

Yeah, I just converted what was there to run once, to loop through multiple times and edited the topic change each time rather than publishing all the values to the same topic without noting that the device_folder was a full path, not just the folder name (aka sensor id). That’s (hopefully) fixed in last nights effort.

1 Like

I knew you were the man to talk to, thank you so much you solved it working like a dream.

Just as a matter of interests, was not able to get the emonpi in South Africa,managed to get all the bits from hobbie shops and it works :slight_smile: A big thank you to pb66 Paul you managed to get the last part working.

to others my setup

One idea i have being toying with is to use a 8 port relay kit, so that when a temp reaches a certain deg it would turn on the relay on the board and keep it on for a predefined time.

Was wondering if you had a second, to have a quick look again, when i run the script, relay turns on, and stays on, even if i stop, the script stays on, temp is way below the value. Also would it be possible, to Select a certain temp sensor, to monitor , if that value goes high, then turn on the relay pin?

#!/usr/bin/env python3

import os
import glob
import time
from time import sleep
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

GPIO.setup(13, GPIO.OUT)
GPIO.output(13, GPIO.LOW)

base_dir='/sys/bus/w1/devices/'
device_folder=glob.glob(base_dir + '28-*')[0]
device_file=device_folder + '/w1_slave'

set_temp=39.222, 72

def temp_raw():
    f=open(device_file, 'r')
    lines=f.readlines()
    f.close()
    return lines

def read_temp():
    lines=temp_raw()
    while lines[0].strip() [-3:] != 'YES':
        time.sleep(0.2)
        lines=temp_raw()
    temp_output=lines[1].find('t=')
    if temp_output != -1:
        temp_string=lines[1].strip() [temp_output+2:]
        temp_c=float(temp_string) / 1000
        temp_f=temp_c * 9.0 / 5.0 + 32.0
        return temp_c, temp_f
while True:
    if read_temp()>= set_temp:
        sleep(30)
        GPIO.setup(13, GPIO.IN)
        exit()  ```

I have this so far ,no errors, but relay does not turn on :frowning:


import os
import glob
import time
from time import sleep
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

GPIO.setup(13, GPIO.OUT)
GPIO.output(13, GPIO.LOW)

Sensors = {'28-020e9177ec79',}

set_temp=22.22

def read_temp(sensorid):
    valid = False
    temp = 0
    device_file = '/sys/bus/w1/devices/' + sensorid + '/w1_slave'
    with open(device_file, 'r') as f:
        for line in f:
            if line.strip()[-3:] == 'YES':
                valid = True
            temp_pos = line.find(' t=')
            if temp_pos != -1:
                temp = float(line[temp_pos + 3:]) / 1000.0

    if valid:
        return temp
    else:
        return None


while True:
    if Sensors.iteritems()>= set_temp:
        GPIO.setup(13, GPIO.IN)
        sleep(30) ```

Can you tell us more about what the end game is? What do you want this all to do, not just this step, but the whole temperature and relay implementation, you seem to have ditched the work we did previously and reverted to the original again and then something inbetween.

That’s because all you have coded is turning the relay on when it reaches temp, you have no code to return it to off, it’s not “auto-return” you need to tell it exactly what to do eg for a heater you might use

if under 18°C turn heater on
else if over 22°C turn heater off

The state of the GPIO output will stick at what ever it is when the script exits unless you add a “turn heater off” line before exiting, note if the script stops ungracefully (crashes or is killed) the current state would still stick as the end code isn’t run.

Do you want different sensors to control different pins (relays) ? or multiple sensors reporting and just one specific sensor doing the relay? or do you just want one sensor and one relay?

Hi no that code you wrote form me i am using as is not changed anything thank you again.

the end game, is to use the sensors, to monitor the equipment, if the battery box were to get to hot turn on a relay , to run a fan. Inverter to hot turn on a fan ect.i am looking at runing a separate script, relay-fan.py to monitor the scrit you wrote with the SENSORS-A ect, i would like to use a seperate pin on the relay per sensor.

Now for an example i will take SENSOR-A, label it battery, if that temp, rises over 30deg C, it will run the relay on pin lets say IN1 , SENSOR-B , label Inverter gets over 40 deg C turn on IN2, ect C,D E.F ect

As you can see, original script running like a dream, want to do a seperate script, to do the control, what i tried to do was, cut and paste bits, to create a new script “relay-fan.py”

Correct Yes

Why must it be a separate script? IMO that is complicating things. I would favour just adding the control part after each sensor is read in the script we have.

#!/usr/bin/python3

import glob
import time
import paho.mqtt.publish as publish
import RPi.GPIO as gpio

Broker = '127.0.0.1'
auth = {
    'username': 'emonpi',
    'password': 'emonpimqtt2016',
}

Sensors = {{'name':'SENSOR_A','id':'28-800000abc123','pin':1,'on':20,'off':15},
           {'name':'SENSOR_B','id':'28-800000def456','pin':2,'on':20,'off':15},
           {'name':'SENSOR_C','id':'28-800000abc456','pin':3,'on':20,'off':15}}

def read_temp(sensorid):
    valid = False
    temp = 0
    device_file = '/sys/bus/w1/devices/' + sensorid + '/w1_slave'
    with open(device_file, 'r') as f:
        for line in f:
            if line.strip()[-3:] == 'YES':
                valid = True
            temp_pos = line.find(' t=')
            if temp_pos != -1:
                temp = float(line[temp_pos + 3:]) / 1000.0

    if valid:
        return temp
    else:
        return None

gpio.setmode(gpio.BOARD)

for sensor in Sensors:
    gpio.setup(sensor['pin'], gpio.OUT)
    gpio.output(sensor['pin'], gpio.HIGH)

while True:
    for sensor in Sensors:
        temp = read_temp(sensor['id'])
        if temp is not None:
            pub_topic = 'emon/Temperatures/' + sensor['name'] + '/values'
            publish.single(pub_topic, str(temp),
                    hostname=Broker, port=1883,
                    auth=auth,)
            if temp >= sensor['on']:
                gpio.output(sensor['pin'], gpio.LOW)
            elif temp <= sensor['off']:
                gpio.output(sensor['pin'], gpio.HIGH)

    time.sleep(6)

The usual warning applies as I’ve just knocked this out without testing.

You need to give some thought to what should happen if a sensor is uncontactable or errors, ie if temp IS None (for a prolonged time?), what should the fan be doing then?

With this arrangement it would also be very easy to add a line or 2 to publish the current (expected) relay state, ie what the pin output is, this would assume the relay and fan are connected and working to the pin status.

Note the bogus pin numbers I have used in the revised “Sensors” layout, the “on” and “off” are the setpoints and can be ints or floats, be sure not to quote those values (making them strings). You also need to check if you are using BOARD or BCM GPIO pin numbering and set the gpio.setmode(gpio.BOARD) line to suit.

I’m off out for most of the day now so won’t be able to assist much further today I’m afraid.

[edit - Oh, and I have assumed the pins will be high at rest (off) and held active low (on) for the relays, if that’s wrong, change both HIGH’s to LOW’s and the one LOW to HIGH.

1st Thank you so much for the time you spent , with helping me, i really do appreciate allot.

You 100% right does make more sense.I did not want to mess with the original script that you wrote.

I would think for safety that the fan should turn on and run, better cold than too hot ?

That is a fantastic idea the state of the fan as a ON or OFF condition. ( SENSOR A- FAN ON/OFF) it takes out the guess work as to the state of the fan.

As per script ill use (gpio. board ) the physical pin numbering of the board if i understand that correctly.

So i am using pin BOARD=31,33,35 BMC = GPIO 6, GPIO 13, GPIO 19

           {'name':'SENSOR_B','id':'28-800000def456','pin':2,'on':20,'off':15},
           {'name':'SENSOR_C','id':'28-800000abc456','pin':3,'on':20,'off':15}} ```

I take it the 20 and 15 ints or floats that’s where i have no idea.
I take it if i look at the code, 20 deg will turn on, and 15 deg turn off, but i take it, i cannot use it like that 20 and 15 needs to be changed (total lost with that, searched hours on google to try and find info that made sense to me, sorry not a programing person but i really want to learn.

Thank you again for all the help, much appreciated

Pins have been changed to

Sensors = {{'name':'SENSOR_A','id':'28-800000abc123','pin':31,'on':20,'off':15},
          {'name':'SENSOR_B','id':'28-800000def456','pin':33,'on':20,'off':15},
          {'name':'SENSOR_C','id':'28-800000abc456','pin':35,'on':20,'off':15}} ```

For our purpose here (although the datatype can be int or float) i was simply saying that the on and off values can be whole numbers or decimal, they are the setpoints in Centigrade (sorry I omitted that small detail) so you can set the fan to come on at 40°C and off at 33.333333°C should you choose, the values I put in there (20 and 15) were just random values, obviously the off needs to be lower than the on setpoint so that the fan comes on when hot and off again once cooled.

Below I have added publishing the fan status, unfortunately emoncms only understands numeric data so it has to be “1” and “0” for on and off. There are 2 options, if you look at the publish lines there are 2 at each of 3 points, one of which (at each point) is commented out with a “#”. As it stands it will publish in a way that gives you 2 nodes, one “Temperatures” and the other “Fans” as this is close to what you have, if you switch over to the commented versions (by removing the “#” and adding a “#” to the beginning of the previous line) it will create as many nodes as you have sensor and fan pairs, each node will have 2 values, status and temperature, this might be preferable to you maybe? Once you decide you can just delete the 3 unused lines.

#!/usr/bin/python3

import glob
import time
import paho.mqtt.publish as publish
import RPi.GPIO as gpio

Broker = '127.0.0.1'
auth = {
    'username': 'emonpi',
    'password': 'emonpimqtt2016',
}

Sensors = {{'name':'SENSOR_A','id':'28-800000abc123','pin':1,'on':20,'off':15},
           {'name':'SENSOR_B','id':'28-800000def456','pin':2,'on':20,'off':15},
           {'name':'SENSOR_C','id':'28-800000abc456','pin':3,'on':20,'off':15}}

def read_temp(sensorid):
    valid = False
    temp = 0
    device_file = '/sys/bus/w1/devices/' + sensorid + '/w1_slave'
    with open(device_file, 'r') as f:
        for line in f:
            if line.strip()[-3:] == 'YES':
                valid = True
            temp_pos = line.find(' t=')
            if temp_pos != -1:
                temp = float(line[temp_pos + 3:]) / 1000.0
    if valid:
        return temp
    else:
        return None

def publish_data(topic, value):
    publish.single(topic, str(value),
                    hostname=Broker, port=1883,
                    auth=auth,)
    return

gpio.setmode(gpio.BOARD)

for sensor in Sensors:
    gpio.setup(sensor['pin'], gpio.OUT)
    gpio.output(sensor['pin'], gpio.HIGH)

while True:
    for sensor in Sensors:
        temp = read_temp(sensor['id'])
        if temp is not None:
            publish_data('emon/Temperatures/' + sensor['name'] + '/values', temp)
            #publish_data('emon/' + sensor['name'] + 'Temperature/values', temp)
            if temp >= sensor['on']:
                gpio.output(sensor['pin'], gpio.LOW)
                publish_data('emon/Fans/' + sensor['name'] + '/values', 1)
                #publish_data('emon/' + sensor['name'] + '/Status/values', 1)
            elif temp <= sensor['off']:
                gpio.output(sensor['pin'], gpio.HIGH)
                publish_data('emon/Fans/' + sensor['name'] + '/values', 0)
                #publish_data('emon/' + sensor['name'] + '/Status/values', 0)

    time.sleep(6)

Hi @pb66 i receive the following error when running the script:

Traceback (most recent call last):
  File "mqtt-temp", line 16, in <module>
    {'name':'SENSOR_C','id':'28-020e9177ec79','pin':35,'on':40,'off': 33.333333}}
TypeError: unhashable type: 'dict'
pi@emonpi:/usr/local/bin $

@tonertiffi did you try and google the error message? so Google TypeError: unhashable type: 'dict' and see what you might find - a number of results do appear (I don’t know the answer BTW).