Writing automations in pure JavaScript—is this possible?

Hey there, new to HA. I spent the last week or so setting up HA and toying around with Node-RED. I created a very convoluted flow that handles my motion sensors, but all throughout I kept asking myself why I couldn’t just write a bunch of JavaScript code to the same end. I am a programmer, so that would feel more natural to me, and most of the time I spent using Node-RED was actually me trying to wrangle its nodes and data flow to do what I wanted it to do. Storing state was a particularly difficult bit, I solved it by using the state machine node but it took a lot of tinkering. Debugging is another particularly painful story in my experience with Node-RED, as it’s hard to inspect exactly what you want to inspect or curate the debug messages that you get, unless you spend effort setting up and tearing down debug nodes.

If I could write the same code using JavaScript and the async/await pattern, I feel I’d end up more productive and with a resulting automation that is easier for me to inspect.

I tried searching around a bit, but I haven’t found much to this end. What I’m picturing is something just like Node-RED, where you can write scripts using a simple API that lets you access events and entities. I really love the simplicity of Node-RED where deploying a flow just takes a button click, something similar to that but with code would be awesome.

I imagine this all could be done by writing my own software and using the Websocket JS API but again that would require me to manage the scripts themselves, set them up and launch them as daemons, and manage their lifecycle if I have to update them or if something crashes. It’d all be easier with a “managed” approach similar to what Node-RED provides.

I wonder if anything like this exists for HA?

I’m not sure about JS specifically, but you could certainly write a connector using the HA API. Would probably be a lot of work. Maybe someone did this already.

That said, there’s something like that for Python at least:

It’s really nice, I use it for almost all my automation and scripts now. It just feels so much more natural to write it in code compared to the built-in HA automations or NodeRed.

You might want to take a look at Tileboard too. It’s a Javascript UI over Home Assistant, using the Websocket API. I use it as my main UI. Not exactly what you needed, but it could be a starting point for writing your own JS code around the HA websockets API.

There is also a C# api. New NetDaemon Release: Use C# to automate Home Assistant - Home Assistant

If you use the function node then you can write JavaScript.
Regarding debugs being hard? Tell us the problems instead of dramatizing it and we can help you how to use the debug tools in Node red.

No drama intended. The main struggle I’ve had with debug nodes is how much effort it takes to set them up and make sure they output the right thing (since my choice is between a single field on the message object, or the whole object, or writing an expression using jsonata). Next to that, the debug panel has been slightly difficult to use mostly because it’s cramped and can get crowded quickly when some of your nodes are overly chatty (whereas for example the chrome devtools console collapses multiple messages into one when they’re the same). So it’s just a bunch of paper cuts adding up to some friction. Compared to a scripting language where you can just print the data you’re interested in with very few keystrokes, they are a bit of extra effort in my opinion.

Thanks! My python is a bit rusty but that API looks very good. In the absence of a JavaScript version that might be what I use.

If you have a chatty node then I suggest you use the trigger block node.

This will let one message pass and block all others meaning you can inspect the debug for any length of time then reset the block when you need a new debug message.

[{"id":"faa7554e3b2390b7","type":"debug","z":"14ca354715bc92f3","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":610,"y":680,"wires":[]},{"id":"c4ed3ba8895f36e7","type":"inject","z":"14ca354715bc92f3","name":"Chatty node","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"date","x":190,"y":680,"wires":[["fe8428efd0cbd83e"]]},{"id":"9909ce9dbfca246a","type":"inject","z":"14ca354715bc92f3","name":"reset","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"reset","payloadType":"str","x":220,"y":580,"wires":[["fe8428efd0cbd83e"]]},{"id":"fe8428efd0cbd83e","type":"trigger","z":"14ca354715bc92f3","name":"","op1":"","op2":"0","op1type":"pay","op2type":"str","duration":"0","extend":false,"overrideDelay":false,"units":"ms","reset":"reset","bytopic":"all","topic":"topic","outputs":1,"x":420,"y":680,"wires":[["faa7554e3b2390b7"]]}]

I always use complete message since only getting one part of the message will cause you to make a mistake.
Although I’m not a JavaScript developer (but many other languages), I do enjoy Node Red for the mix of coding and visual aid of what is going on, message variables and the global variables. It all makes it perfect in my opinion.