Problems with GPIO push button on self build emonPi

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

My bad, in my head I had changed the Sensors format to a list of dicts but failed to make that edit. Change the 2 outer curly braces to square bracket like so

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}]

I will try and keep an eye on the forum in case you have further issues, but I have quite a bit on this weekend so I do not know if or when I might be about yet.

You are truly brilliant @pb66 .:smiley: Attached screen shots, from 1st to last, the relay does activate and deactivate. Never had to change anything in the code except for the [ ].
Just that i understand readings go red, take it, it cannot read the state of the pin?
When state turns back to 0 it carries on reading it no problem.
Thank you very much.

That makes sense, I had just added the publish line to the change of pin status code so it only publishes when the state changes, that is how I would expect a “status” to work on MQTT, but you are right, emoncms expects a constantly updating value I guess, for graphs etc to view better.

it’s an easy fix, change the existing control code like so

            if temp >= sensor['on']:
                gpio.output(sensor['pin'], gpio.LOW)
                sensor['status'] = 1
            elif temp <= sensor['off']:
                gpio.output(sensor['pin'], gpio.HIGH)
                sensor['status'] = 0

        publish_data('emon/Fans/' + sensor['name'] + '/values', sensor['status'])
        #publish_data('emon/' + sensor['name'] + '/Status/values', sensor['status'])

The status variables also needs defining before entering the main loop, just in case a temp reading is None and it tries to publish a status before it gets a valid read. Add sensor['status'] = 0 to the gpio setup code immediately before entering the main loop, eg

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

while True:

Hi Paul,

Get the following error

pi@emonpi:/usr/local/bin $ python mqtt-temp

File “mqtt-temp”, line 50

if temp >= sensor[‘on’]:

^

IndentationError: unexpected indent

pi@emonpi:/usr/local/bin $

That’s most likely a copy and paste error. Python is very fussy about indentation, looking at the script there are 4 levels of indentation (plus no indentation). the if temp >= sensor['on']: line is on the 3rd level of indentation which means it probably must have 3 tabs or 12 spaces depending on what style you are using.

Beware of stray white space and or line endings altering things from what you see to what is seen by Python.

If you cannot resolve the problem you need to post the code you have leading up to and after the point it says is at fault as the required indention is defined by the code around it.

Hi @pb66

  File "mqtt-temp", line 55
    publish_data('emon/Fans/' + sensor['name'] + '/values', sensor['status'])
                                                                            ^
IndentationError: unindent does not match any outer indentation level
pi@emonpi:/usr/local/bin $
    for sensor in Sensors:
        temp = read_temp(sensor['id'])
        if temp >= sensor['on']:
                gpio.output(sensor['pin'], gpio.LOW)
                sensor['status'] = 1
        elif temp <= sensor['off']:
                gpio.output(sensor['pin'], gpio.HIGH)
                sensor['status'] = 0
            publish_data('emon/Fans/' + sensor['name'] + '/values', sensor['status'])
            #publish_data('emon/' + sensor['name'] + '/Status/values', sensor['status'])
            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)

Well yes there are some indentation errors there, for some reason you have duplicated some code one level in

#!/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)
    sensor['status'] = 0

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)
                sensor['status'] = 1
            elif temp <= sensor['off']:
                gpio.output(sensor['pin'], gpio.HIGH)
                sensor['status'] = 0

        publish_data('emon/Fans/' + sensor['name'] + '/values', sensor['status'])
        #publish_data('emon/' + sensor['name'] + '/Status/values', sensor['status'])

    time.sleep(6)

Convinced you a genius :smiley:

In my effort i managed to break this, it does not update the values, if i hit refresh it works , go out, go back in values updated,never turns red

Check pc time bottom left:smiley: