PiFace CAD - a different request

I appreciate the recent post of the PiFace node allowing use of the display on the RasPi's PiFace CAD shield.

Is there also a node out there which allows access to the buttons also?

It is just having the display (finally) usable via NR, allowing use of the buttons would really make the flow look schmik (Nice) as it would allow scrolling, and other sorts of things.

Thanks in advance.

You could use the exec node to trigger the python library scripts to read the switches.

Some information on interrupts here:
http://piface.github.io/pifacecad/example.html

1 Like

Looks like I am going to have to do some serious learning.

Thanks.

You could easily write a python script utilizing the python library and subscribe to button events, publish those to a mqtt broker -> NR
You could start the script with the exec node and monitor that it is running (by adding some heartbeat function to the script) and then restart it if it for some reason should crash/fail

Yes, and I kind of said I will do that - when I get time.

But that is some serious learning I need to do.

In the past I seem to remember trying and read that the buttons are HIDDEN from external access with the code supplied.

To which I decided it isn't going to happen.

It would be nice/r if it could be all handled by a NR node.
Rather than me writing scripts (Python?) on the machine which get invoked by NR and return their results.

Anyway, again: Thanks. It will require some serious concurrent times to do. Which I think is not going to happen soon. :frowning:

You could have a python script write to a file when an interrupt occurs and watch the file from Node-red. Using node-red alone you would have to poll the switches, which takes a lot of processor time, depending on the poll frequency.

Of course for the people suggesting you write a python script need to be aware that it requires knowing and understanding Python, and while it’s a popular language it’s (sadly) not at the stage where everyone knows it or can use it freely.

1 Like

I did not say I am unwilling to help. But it seems there was actually not such urgency if I understood it correctly. Either way, someone has to spend some time, I would have to spend less since I am kind of used to Python. On the other hand, I do not have a PiFace so for me, no real interest except I'm offering some help to solve a missing feature. But if a node enhancement is wanted, my best advice is to contact the related node author.

Otherwise the Python library seems to have what is needed:

Instead of polling the switches we can use the SwitchEventListener to register actions that we wish to be called on certain switch events.

No polling, no writing to files needed, just nice callbacks that can be sent via mqtt. I can make a shot at it if there is interest, otherwise I will dive into something else

1 Like

Good point!, I forgot MQTT :slight_smile:

Sorry @krambriw it isn't I meant anything bad.

It is one of those tasks that I would like to resolve, but as it is so .... vague.... (skill requiring) of me at this time and I am so overwhelmed with just as many other tasks of the same priority it is difficult to maintain focus on it.

I would appreciate help, but in saying that, I am not expecting you to write the code for me.
It is I am just not with it just now.

I live in Oz and these bush fires - though not near me - are sort of worrying in their own way and are also distracting to me at times.

@Trying_to_learn

Dear Andrew, no problems at all, sorry and sad for those wild fires, worst ever I think? Terrible, really.

I took some time to write a small python script that you can test when time and if you like. It is rather straight forward, it connects to a mqtt broker (I assumed in the same Pi, otherwise you have to edit the ip). It loads the pifacecad python library, writes a welcome message to the lcd. When you press a button you should see it's number on the lcd and receive a mqtt message in Node-RED

To make it happen:

  1. install the pifacecad python library, see here http://piface.github.io/pifacecad/installation.html
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install python{,3}-pifacecad
  1. Install paho mqtt client (if you do not have it already)
sudo pip install paho-mqtt
  1. Create a new file piFaceCAD.py in /home/pi/ with the following content (and change ip if necessary)
# coding: utf-8

import pifacecad
import time
import paho.mqtt.client as mqtt


def update_pin_text(event):
    event.chip.lcd.set_cursor(13, 0)
    event.chip.lcd.write(str(event.pin_num))
    send_mqtt_message("pifacecad", "You pressed button:"+str(event.pin_num))


def send_mqtt_message(topic, msg):
    for i in range(5):
        try:
            result, mid = client.publish(topic, msg, 0)
            #print ('result', result)
            if result == 0:
                break
        except:
            print ("retrying...")


def on_connect(client, obj, flags, rc):
    client.subscribe("cmds", 0)


def on_subscribe(client, userdata, mid, granted_qos):
    print ('Subscribed:', userdata, mid, granted_qos)
    print ('We are here, waiting for commands...')


def on_message(mosq, obj, msg):
    global abort
    try:
        event = msg.payload.decode("utf-8").split('.')
        #print (event)
        if event[0] == 'abort':
            listener.deactivate()
            abort = True
    except:
        pass
        
abort = False
client = mqtt.Mosquitto()
client.on_connect = on_connect
client.on_message = on_message
client.on_subscribe = on_subscribe
client.connect("127.0.0.1", 1883, 60)
client.loop_start()

cad = pifacecad.PiFaceCAD()
cad.lcd.write("Welcome to your piFaceCAD! You pressed: ")
listener = pifacecad.SwitchEventListener(chip=cad)
for i in range(8):
    listener.register(i, pifacecad.IODIR_FALLING_EDGE, update_pin_text)
listener.activate()

while not abort:
    time.sleep(0.5)
  
client.loop_stop()
client.disconnect()
del client
exit(0)

To try it out, you can import/use the following flow. To start or abort the script, just click on the buttons. To make it "visible" the script is started on the display nbr 0. I hope it works (not able to test with the piface), if so, you should see the messages in the NR debug window

[{"id":"d4ed32d4.b091a","type":"exec","z":"ae89c6f4.025a58","command":"export DISPLAY=:0 && lxterminal -e python /home/pi/piFaceCAD.py","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":700,"y":100,"wires":[[],[],[]]},{"id":"e5597030.9c372","type":"inject","z":"ae89c6f4.025a58","name":"Start script","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":250,"y":100,"wires":[["d4ed32d4.b091a"]]},{"id":"9f5a12c4.c3359","type":"inject","z":"ae89c6f4.025a58","name":"Abort script","topic":"","payload":"abort","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":260,"y":180,"wires":[["2b2c9050.0d932"]]},{"id":"2b2c9050.0d932","type":"mqtt out","z":"ae89c6f4.025a58","name":"","topic":"cmds","qos":"","retain":"","broker":"75eba16c.094f9","x":500,"y":180,"wires":[]},{"id":"d1ff0302.d0d1a","type":"mqtt in","z":"ae89c6f4.025a58","name":"","topic":"pifacecad","qos":"0","datatype":"auto","broker":"75eba16c.094f9","x":250,"y":260,"wires":[["e16edbaf.068c18"]]},{"id":"e16edbaf.068c18","type":"debug","z":"ae89c6f4.025a58","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":520,"y":260,"wires":[]},{"id":"75eba16c.094f9","type":"mqtt-broker","z":"","name":"","broker":"127.0.0.1","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]

1 Like

Wow! Thanks.

I shall try to look at it this after noon.

I just woke up and it is raining! (Hurray! - and I believe it is state wide so that is even better)

The python script. That is similar to the one which came with the board, but you just added a bit of MQTT stuff - right?

Neat. As I said I will try to get a look this afternoon.

This is the way I have integrated many services & things with NR where there was no available node to grab. I have actually a python script also for Telegram and OneWire even though there now is a number of nodes for those. In many cases the scripts are more advanced using threads etc and with enhanced monitoring & control by NR. To run them "visible" is not really needed but it is nice when you VNC into a headless RPi, you can watch the script doing it's task. In one RPi I have 5 python scripts running since years this way

Anyway, the script you got is based on one of my others, I have no idea what you got with the board, I just used the info from the python library page

Hope it works!

(Sorry, I woke up with the usual idiot hat on.)

Don't underestimate my stupidity. It constantly sets new levels. :wink:

Ok, I imported the flow.
The MQTT broker is another machine. So I changed the IP address.
I run the flow and it seems to be running.
The display is 2 x 16 (or 16 x 2). All I see is: "Welcome to your "
Pressing the buttons I get replies, but they are muddled up with the original message.

But..... In your screen shots, you show your machine with a terminal open "python".

I'm guessing that is just an output from python being subscribed to.....
There's a problem.

Where is the "topic" being set that is being used to send these messages?
I can't resolve how/where it is set.

Needing to have internet access to install this, I can't use the RasPi alone. It needs to be headless (as it will be anyway) and remotely controlled.

The `DEBUG` node is not saying a thing when I press buttons.

Stupid me. I'll change the MQTT server details in the MQTT - IN node.

Ok, it is working. Though I get about 10 messages when I press a button. I can work with that.

Can you please tell me how to set the topic to which the information is published?

I've also worked out that the console is opened by the exec node.
export DISPLAY=:0 && lxterminal -e python /home/pi/piFaceCAD.py

(Not your fault but there are/seem to be problems with the display displaying more than 16 characters.... But not a problem. I won't need it when I use the script anyway)

Dear Andrew, not bad! You got it working, that's a first important step!!

I did not know about the size of the display, so I wrote too many chars in a string. It's in the script, this line here:

cad.lcd.write("Welcome to your piFaceCAD! You pressed: ")

You can just change it like:

cad.lcd.write("You pressed: ")

So anytime you want to write something to the lcd you can use the cad.lcd.write() command. Once you feel comfortable with the script I'll show you how you can send such messages from NR to be displayed on the lcd

This is the mqtt topic ("cmds") where you send commands or messages (currently only abort) to the script

client.subscribe("cmds", 0)

This is the topic ("pifacecad") where the script is publishing messages to

send_mqtt_message("pifacecad", "You pressed button:"+str(event.pin_num))

You can change them to anything you like

No problem about not knowing the size of the display.

I changed the topics (finally did find them) to are more understandable:
PIFACE_CMDS and PIFACE_BUTTON

I use upper case only to keep things constant.

This is the script now:

# coding: utf-8

import pifacecad
import time
import paho.mqtt.client as mqtt


def update_pin_text(event):
    event.chip.lcd.set_cursor(13, 0)
    event.chip.lcd.write(str(event.pin_num))
    send_mqtt_message("PIFACE_BUTTON", str(event.pin_num))


def send_mqtt_message(topic, msg):
    for i in range(5):
        try:
            result, mid = client.publish(topic, msg, 0)
            #print ('result', result)
            if result == 0:
                break
        except:
            print ("retrying...")


def on_connect(client, obj, flags, rc):
    client.subscribe("PIFACE_CMDS", 0)


def on_subscribe(client, userdata, mid, granted_qos):
    print ('Subscribed:', userdata, mid, granted_qos)
    print ('We are here, waiting for commands...')


def on_message(mosq, obj, msg):
    global abort
    try:
        event = msg.payload.decode("utf-8").split('.')
        #print (event)
        if event[0] == 'abort':
            listener.deactivate()
            abort = True
    except:
        pass
        
abort = False
client = mqtt.Mosquitto()
client.on_connect = on_connect
client.on_message = on_message
client.on_subscribe = on_subscribe
client.connect("192.168.0.99", 1883, 60)
client.loop_start()

cad = pifacecad.PiFaceCAD()
cad.lcd.write("Welcome to your piFaceCAD! You pressed: ")
listener = pifacecad.SwitchEventListener(chip=cad)
for i in range(8):
    listener.register(i, pifacecad.IODIR_FALLING_EDGE, update_pin_text)
listener.activate()

while not abort:
    time.sleep(0.5)
  
client.loop_stop()
client.disconnect()
del client
exit(0)

This is the flow I have - basic one:
(Nodes needed: node-red-contrib-simple-gate)
More for basic control of what is happening.

[{"id":"20f34bd1.6a0464","type":"inject","z":"cc585130.29b7e8","name":"","topic":"","payload":"This is a test","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":410,"y":880,"wires":[["c8333c.caa94cc8"]]},{"id":"c8333c.caa94cc8","type":"change","z":"cc585130.29b7e8","name":"","rules":[{"t":"set","p":"delay","pt":"msg","to":"0","tot":"num"},{"t":"set","p":"position","pt":"msg","to":"1,1","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":650,"y":880,"wires":[["118d9066.a076c"]]},{"id":"118d9066.a076c","type":"function","z":"cc585130.29b7e8","name":"Build MQTT message","func":"msg.payload = {\n    payload:msg.payload,\n    delay:msg.delay,\n    position:msg.position\n}\nreturn msg;","outputs":1,"noerr":0,"x":880,"y":950,"wires":[["99948203.32add","82472447.89f28"]]},{"id":"99948203.32add","type":"mqtt out","z":"cc585130.29b7e8","name":"","topic":"PFC_LCD","qos":"","retain":"","broker":"c97b6780.72589","x":1110,"y":950,"wires":[]},{"id":"6c85fb2b.30082c","type":"mqtt in","z":"cc585130.29b7e8","name":"","topic":"PFC_LCD","qos":"2","datatype":"auto","broker":"c97b6780.72589","x":140,"y":470,"wires":[["5d881b63.b2030c","5cd50f9e.41f8a8"]]},{"id":"5cd50f9e.41f8a8","type":"json","z":"cc585130.29b7e8","name":"","property":"payload","action":"","pretty":false,"x":290,"y":470,"wires":[["9dbf0935.d41188","31053769.d90578"]]},{"id":"31053769.d90578","type":"function","z":"cc585130.29b7e8","name":"Build message","func":"let pos = msg.payload.position;\nlet pld = msg.payload.payload;\nlet temp = pos + ':\"' +  pld + '\"';\nmsg.delay = msg.payload.delay;\nmsg.payload = temp;\nreturn msg;","outputs":1,"noerr":0,"x":450,"y":470,"wires":[["f65ec48a.bae2c","9456039d.96cef8","e47a1494.e123b"]]},{"id":"9456039d.96cef8","type":"function","z":"cc585130.29b7e8","name":"Make seconds.","func":"//msg.delay = parseInt(msg.payload.delay);\n\nnode.warn(msg.delay);\n\nif (msg.delay > 0)\n{\n    msg.delay = msg.delay * 1000;\n    node.warn(msg.delay);\n    return msg;\n}\n\n// payload.delay","outputs":1,"noerr":0,"x":650,"y":490,"wires":[["c3d5d766.2c932","6b9a665c.541f18"]]},{"id":"c3d5d766.2c932","type":"delay","z":"cc585130.29b7e8","name":"","pauseType":"delayv","timeout":"10","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":630,"y":530,"wires":[["559af61b.1ef19"]]},{"id":"559af61b.1ef19","type":"change","z":"cc585130.29b7e8","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"OFF","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":880,"y":530,"wires":[["e47a1494.e123b"]]},{"id":"e47a1494.e123b","type":"switch","z":"cc585130.29b7e8","name":"Switch","property":"payload","propertyType":"msg","rules":[{"t":"neq","v":"OFF","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1060,"y":470,"wires":[["c73cf27c.fecfc"],["ed66b5c2.8a7a18"]]},{"id":"c73cf27c.fecfc","type":"gate","z":"cc585130.29b7e8","name":"","controlTopic":"HALT","defaultState":"open","openCmd":"GO","closeCmd":"STOP","toggleCmd":"toggle","defaultCmd":"default","persist":false,"x":1240,"y":470,"wires":[["3d749079.fb982","c4db9353.f211e8"]]},{"id":"ed66b5c2.8a7a18","type":"exec","z":"cc585130.29b7e8","command":"/home/pi/PiFace/LCD_off.sh","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Turn off light & Wipe Display","x":1300,"y":530,"wires":[[],[],[]]},{"id":"3d749079.fb982","type":"pfc_lcd","z":"cc585130.29b7e8","name":"Display","x":1420,"y":470,"wires":[]},{"id":"c97b6780.72589","type":"mqtt-broker","z":"","name":"MQTT Host","broker":"192.168.0.99","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"20","cleansession":true,"birthTopic":"SOM","birthQos":"2","birthPayload":"'Awaiting PiFace'","closeTopic":"","closePayload":"","willTopic":"EOM","willQos":"0","willPayload":"'PiFace telemetry failure'"}]

This is the flow to read the buttons:
Node needed (node-red-contrib-repeat)

[{"id":"15bee644.50e7c2","type":"inject","z":"710ca09a.8302a8","name":"Start script","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":true,"onceDelay":"1","x":140,"y":120,"wires":[["b6f18359.433dc8"]]},{"id":"b6f18359.433dc8","type":"exec","z":"710ca09a.8302a8","command":"export DISPLAY=:0 && lxterminal -e python /home/pi/piFaceCAD.py","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":580,"y":120,"wires":[[],[],[]]},{"id":"73cbc1ca.86f548","type":"mqtt in","z":"710ca09a.8302a8","name":"","topic":"PIFACE_BUTTON","qos":"0","datatype":"auto","broker":"c97b6780.72589","x":160,"y":380,"wires":[["46460da3.617224","c59b6c53.4d347"]]},{"id":"c59b6c53.4d347","type":"repeat","z":"710ca09a.8302a8","name":"","repetitions":"1","elseOutput":false,"outputs":1,"x":370,"y":380,"wires":[["e50784b9.6ffb4","9ac54bf.4dbceb8"]]},{"id":"9ac54bf.4dbceb8","type":"debug","z":"710ca09a.8302a8","name":"After Repeat","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":550,"y":340,"wires":[]},{"id":"c97b6780.72589","type":"mqtt-broker","z":"","name":"MQTT Host","broker":"192.168.0.99","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"20","cleansession":true,"birthTopic":"SOM","birthQos":"2","birthPayload":"'Awaiting PiFace'","closeTopic":"","closePayload":"","willTopic":"EOM","willQos":"0","willPayload":"'PiFace telemetry failure'"}]

So I just then put a switch node and split/route the message as per what it is.

Just want to check how I get rid of the extra console which is opened.
I thought it was in the exec node but when I deleted the first part before the && it didn't work. Well, it possibly will now I said it didn't.
And not display the message when the script starts. But I don't think that is too difficult.

Ahh, OK, should be pretty easy. In the exec node, try this instead:

python /home/pi/piFaceCAD.py
1 Like

Thanks.

First, a new thought:
Rather than having the file we posted, could I put it in this node?
node-red-contrib-python3-function

Thanks for that update.
I am not familiar with the exec node so I was trying:
lxterminal -e python /home/pi/piFaceCAD.py
thinking I needed the terminal open. (It was after the && so it is a new command)

Anyway, I'm moving froward I hope.

Cannot guarantee, it's up to you to try. To start, I assume the pifacecad python library will not be available in that node. Second is that you would then not need the paho stuff either. Third is that the script is running under python, the node is for python3. Well it is your decision but I'm out