Rhasspy, node-red, GPIO, 8 channel relay board - local garage/shop control - Noob learning =D

Hi all,

Beginner here and could use some help, still learning and a ways to go yet!

Looking for a offline, local, voice assistant to control an 8 channel relay board off the RPi GPIOs and stumbled across Rhasspy! I have an electrical and mechanical background but programming and the associated resources are totally new me so please forgive my ineptness on the topic!

I want to control a few lights, fans, and garage doors for now hardwired though RPi GPIOs to the relay board with no additional router or server. Can RPi + Rhasspy achieve this locally (RPi 4 + 32gb card)? I have Rhasspy set up and trained (below) and a basic node-red flow with Rhasspy connected. The rpi-gpio out node is functioning and I can manually fire the relay when I change the initial level of pin from high to low and deploy (GPIOs 32, 36, 38 and 40 are wired to the relay board atm).

Not sure how to connect the dots here; ws node to rpi-gpio out node with inject node and not sure what line of code I need to alter to trigger the High/Low states. Also, not entirely sure if node-red can be run locally once configured and if node-red is even the best solution? I’ve played with a few python command strings I found online to fire the relays in different sequences, is there a way to omit node-red entirely and just parse the json from Rhasspy to python to trigger the relays? And to that, will Rhasspy function offline (or does it need to pull data from the external services)?

I’m sure this is quite novice for most of you but I really appreciate you pointing me in the right direction! It’s a bit of a learning curve and I feel like I’m missing some glaringly obvious steps due my inexperience with programming!

Very excited with the possibilities and really enjoying the challenge, cheers all!! :grinning:

Rhasspy browser sentence:

[ChangeRelayState]
relay_name = ((relay 1 | relay 2 | relay 3 | relay 4) {name}) 
relay_state = (on | off) {state}

turn <relay_state> [the] <relay_name>
turn [the] <relay_name> <relay_state>

Intent JSON:

{
    "entities": [
        {
            "end": 7,
            "entity": "state",
            "raw_end": 7,
            "raw_start": 5,
            "raw_value": "on",
            "start": 5,
            "value": "on",
            "value_details": {
                "kind": "Unknown",
                "value": "on"
            }
        },
        {
            "end": 15,
            "entity": "name",
            "raw_end": 17,
            "raw_start": 8,
            "raw_value": "relay one",
            "start": 8,
            "value": "relay 1",
            "value_details": {
                "kind": "Unknown",
                "value": "relay 1"
            }
        }
    ],
    "intent": {
        "confidence": 1,
        "name": "ChangeRelayState"
    },
    "raw_text": "turn on relay 1",
    "raw_tokens": [
        "turn",
        "on",
        "relay",
        "1"
    ],
    "recognize_seconds": 0.0911380219995408,
    "slots": {
        "name": "relay 1",
        "state": "on"
    },
    "speech_confidence": 1,
    "text": "turn on relay 1",
    "tokens": [
        "turn",
        "on",
        "relay",
        "1"
    ],
    "wakeword_id": null
}

Node-red:

{"intent":{"name":"ChangeRelayState","confidence":1},"entities":[{"entity":"state","value":"on","value_details":{"kind":"Unknown","value":"on"},"raw_value":"on","start":5,"end":7,"raw_start":5,"raw_end":7},{"entity":"name","value":"relay 1","value_details":{"kind":"Unknown","value":"relay 1"},"raw_value":"relay one","start":8,"end":15,"raw_start":8,"raw_end":17}],"slots":{"state":"on","name":"relay 1"},"text":"turn on relay 1","raw_text":"turn on relay 1","tokens":["turn","on","relay","1"],"raw_tokens":["turn","on","relay","1"],"wakeword_id":null,"siteId":"default","sessionId":"d512bbcf-a86f-4ddd-9d79-84c684de93ad","customData":null,"wakewordId":null,"lang":null,"_session":{"type":"websocket","id":"522d2cfd.942b24"},"_msgid":"82a5ed53.1b40c"}

Node-RED is perfectly able to do this, and you can just run Node-RED and Rhasspy on the same Raspberry Pi so the complete system can work offline.

If you prefer Python, you can let your Python program react to your intents with one of:

For GPIO access to trigger the relays in your Python code, use one of:

1 Like

Awesome, glad to hear it’s possible! Thanks for reply @koan, I’ll look into those :slight_smile:

Which method would you recommend? Trying to understand if there are any benefits or drawbacks to node-red vs python intent handler.

With node-red, I’m still trying to understand how to get the json node to fire the gpio out node, what am missing? Do I need to add a command in the ws.node or add additional nodes to the flow?

I’m not sure how to parse the json into python yet either if that’s the preferred method, any suggestions on what I need to add there? I’m diving into YouTube tutorials but it still hasn’t clicked, just signed up for a udemy course as well, hopefully fill in some gaps! Any other suggestions/resources are appreciated!

Well, I have done some work with Node-RED, but I’m more fluent in Python, so that’s what I use now for handling Rhasspy intents. I would recommend rhasspy-hermes-app, but I’m biased, because I wrote it :wink:

I find Node-RED a perfect choice for intent handling if you already use Node-RED for other stuff too, such as automating Home Assistant or any other home automation tasks. But I wouldn’t install Node-RED just for intent handling. Of course it also depends on your programming knowledge: do you know Python or are you more comfortable with the “low-code” approach of graphical programmin in Node-RED?

To parse the JSON in Node-RED, have a look at the change node or the template node to extract specific parts of the JSON such as the relay_name and relay_state slots.

1 Like

Definitely a justified bias! :rofl: that’s awesome, I’ll check it out!!

No experience with either beyond this use case. The UI/flows in Node-Red looked approachable to test this out but ultimately, I’m looking for the simplest solution. However, my only experience with Python is tweaking a few command lines I found online to fire the relays in different sequences with on/off delays in RPi.GPIO.

Haven’t quite figured out how to convert the Rhasspy JSON intent into firing the relays with either method unfortunately :man_facepalming:

The only additional functionality I’d like to add for this use case is to customize the voice commands (keeping it simply for now with relay 1, 2… until it works!) and perhaps adding more relay boards which as I understand it, might be a challenge on RPi once you exceed the GPIO pins. I’ve read through a matrix, I can link up to 8 boards of 8 relays for a total of 64. If that’s possible to control with Rhasspy, I’d like to expand beyond to single relay board and install a few additional listening Pi’s around the house for an off-network, hardwired, “dumb” smart home!

Very cool this exists and I’m excited about the possibilities! Really like the idea of having a reliable, hardwired, voice controlled home that’s not dependent on the internet to function with the added bonus of not being data mined 24/7 lol!!

Thanks again for your help, only a couple weeks into this and I sure wish I knew how to code!!! Excited to learn and trying to find the most efficient method :slight_smile:

Hi @Akoni, you may also be interested in Rhasspy’s sister project voice2json and @JGKK’s Node-RED nodes for it.

1 Like

Well, it’s more fun if you discover it all yourself, so just give it a try, show us the code you have and let us know where you’re stuck. We can help you then.

1 Like

Thanks @koan and @synesthesiam for the replies! I’ll dig into the suggestions and report back :slight_smile:

@synesthesiam, this statement from voice2json has me wondering: Assumptions - A voice command contains at most one intent. Is Rhasspy able to process multiple intents? In my use case, it would be practical to process multiple if able rather than having to pause and initiate the wake word for each relay. I.e. “turn on relay 1, 2 and 4”.

Cheers!

You can write an intent like this with the simplified jsgf syntax that both rhasspy and voice2json use something like:

[light]
items = item1 | item2 | item3 | item4
turn (on | off)  <items>  [<items>] [and <items>]

(not tested) would give you up to three items in one command.

3 Likes

Awesome, thanks! I’ll test this out once I’ve got one relay recognizing and firing from the intent :crossed_fingers:

You guys rock, thx for developing and supporting this! Amazing stuff :handshake:.