@Emil Sorry. Didn't write that it's when I'm in my car on my way home.๐
-
What is it?
Hub TCP server for using the IR module via HTTP.
Both to record of new signals with a given name and to play them back.
Using net since SDK doesn't have the nodejs HTTP-module available.Why?
I really wanted to be able to call my IR module from my phone homescreen or Google Home (via IFTTT). I got it working so I wanted to share it if anyone else find it helpful ๐The code is what could be called a POC, so code feedback and/or changes are totally welcome.
How does it work?
Record a signal GET {ip}:1338?record={name_of_signal} Plays a signal GET {ip}:1338?cmd={name_of_signal} Cancel recording GET {ip}:1338?cancelRecord=trueExample;
call GET 192.168.0.100:1338?record=volume_up Press Volume Up on remote towards IR module returns 200 OK Signal volume_up stored! call GET 192.168.0.100:1338?cmd=volume_up returns 200 OK Signal sent! Volume goes up ๐The code
module.json
{ "name": "IRTCP", "version": "1.0.0" }main.js
// main.js const net = require("net"); const ir = require("ir"); const datastore = require("datastore"); const utils = require("./utils"); const respondToClient = function(c, statusCode, message) { c.write( "HTTP/1.1 " + statusCode + "\r\n" + "\r\n" ); c.write(message); c.end(); } const handleCmd = function(c, cmd) { datastore.get(cmd, function(err, strBuffer) { if (!err && strBuffer) { var signal = new Uint32Array(utils.str2ab(strBuffer)); if (!ArrayBuffer.isView(signal)) { return respondToClient(c, "422 Unprocessable Entity", "Unknown signal"); } ir.play(signal, function(err) { if (!err) { return respondToClient(c, "200 OK", "Signal sent"); } return respondToClient(c, "500 Internal Server Error", "Couldn't send signal"); }); } else { return respondToClient(c, "422 Unprocessable Entity", "Unknown cmd"); } }); } const handleRecord = function(c, name) { /* TODO: add a timeout for listening for complete */ ir.record(); console.log("recording signal..."); ir.on("recordComplete", function(signal) { datastore.put(name, utils.ab2str(signal.buffer), function(err) { if (!err) { console.log("Signal " + name + " stored!"); return respondToClient(c, "200 OK", "Signal " + name + " stored!"); } else { return respondToClient(c, "500 Internal Server Error", "Couldn't store signal"); } }); }); } var server = net.createServer(function(c) { console.log('server connected'); c.on('end', function() { console.log('server disconnected'); }); c.on('data', function(data) { console.log(data); var match = data.toString().match(/GET \/\?.[^ ]*/); if (!match) { return respondToClient(c, "403 Forbidden", "Forbidden method"); } var params = utils.parseParams(match[0].split("GET /?")[1]); if (params.cmd) { return handleCmd(c, params.cmd); } else if (params.record && params.record.length > 0) { return handleRecord(c, params.record); } else if (params.cancelRecord) { ir.cancelRecord(); console.log("recording canceled!"); return respondToClient(c, "200 OK", "Recording canceled!"); } else { return respondToClient(c, "403 Forbidden", "Forbidden params"); } }); }); server.listen(1338, "0.0.0.0", function() { console.log('server bound', server.address().port); });utils.js
const ab2str = function(buf) { return String.fromCharCode.apply(null, new Uint16Array(buf)); } const str2ab = function(str) { var buf = new ArrayBuffer(str.length*2); var bufView = new Uint16Array(buf); for (var i=0, strLen=str.length; i < strLen; i++) { bufView[i] = str.charCodeAt(i); } return buf; } const parseParams = function (s) { var obj = {}; var arr = s.split("&"); var temp; for (i = 0; i < arr.length; i++) { temp = arr[i].split("="); obj[temp[0]] = temp[1]; } return obj; }; exports.ab2str = ab2str; exports.str2ab = str2ab; exports.parseParams = parseParams; -
I had my Matter Bridge commissioned to my Flic hub and all working great,
Accidentally I managed to decommision the bridge from the flic fabric via the iOS Matter settings but it didn't remove from the flic app.
Now I'm in a state where the flic app thinks there is a bridge (and all its associated devices) there but it shows as offline and I can't remove it.
I managed to recommision the Bridge back to flic but now I have a duplicate set of 22 device in my list!
Is there a way I can remove the old bridge from the Flic Hub?
24f86297-d670-4628-8f9d-09b3bef31c63-Screen Shot 2026-01-06 at 8.59.22 AM.png
-
Just got my flic twist and the hub, but canโt get it to turn volume up down (or any other Sonos related actions).
Running on firmware 4.5.1
When I setup Sonos provider on the hub, all my speakers are just listed as โSonosโ with different ipโs.
When I setup Sonos in the provider in the Phone section ( or the hub), there I see the correct speaker names.
Tried all kind of delete/re-add, no luck.
Any clues?
-
I just spent too long trying to figure this out since the documentation is not up to date and the chatGPT bot is just wrong.
Anyways I thought I would share how I am handling my first Flic Duo device to trigger different Home Assistant automations using the different buttons and webhooks . Hopefully this might save other people some time and effort.
main.js var buttonManager = require("buttons"); var http = require("http"); buttonManager.on("buttonSingleOrDoubleClickOrHold", function(obj) { var button = buttonManager.getButton(obj.bdaddr); var clickType = obj.isSingleClick ? "click" : obj.isDoubleClick ? "double_click" : "hold"; var payload = JSON.stringify({ button_name: button.name, click_type: clickType, }); var targetUrl = null; if (button.name === "lock") { targetUrl = "http://XXX.XXX.XX.XX:8123/api/webhook/flic-lock"; } else if (button.name === "auto1") { targetUrl = "http://XXX.XXX.XX.XX:8123/api/webhook/flic-leavingHome"; } else if (button.name === "duo1") { if (obj.buttonNumber === 0) { targetUrl = "http://XXX.XXX.XX.XX:8123/api/webhook/flic-duo1-big"; } else if (obj.buttonNumber === 1) { targetUrl = "http://XXX.XXX.XX.XX:8123/api/webhook/flic-duo1-small"; } } if (targetUrl) { http.makeRequest({ url: targetUrl, method: "POST", headers: {"Content-Type": "application/json"}, content: payload, }, function(err, res) { console.log(""); console.log("Sent to: " + targetUrl); console.log("Name: " + button.name); console.log("ID (bdaddr): " + button.bdaddr); console.log("Serial: " + button.serialNumber); console.log("Click Type: " + clickType); console.log("uuid: " + button.uuid); console.log("key: " + button.key); //console.log("Button #: " + obj.buttonNumber); console.log("Status: " + res.statusCode); }); } }); console.log("Script started");obj.buttonNumber returns 0 for the upper bigger button and 1 for the smaller lower button
You can also perform different automations depending on click type using an if statement where you change the keyword click using something like (YAML):
conditions: - condition: template value_template: "{{ trigger.json.click_type == 'click' }}"The HA automation webhook trigger YAML looks something like:
triggers: - allowed_methods: - POST - PUT local_only: true webhook_id: flic-leavingHome trigger: webhookThis might not be the best way to go about this but I would be interested to hear suggestions for improvements. Now do add the rest of the new buttons and model the dimensions as a 3D STL file. It would be nice if flic also provided this as well.