Fakeroku Emulator

Emulates Roku devices so ECP/SSDP remotes (Harmony, Sofabaton) trigger events in ioBroker

Current Release
1.7.1
Developer
krobi, Pmant, iobroker-community-adapters
License
MIT

This adapter makes ioBroker look like one or more Roku streaming devices on your local network. A remote control that speaks Roku's protocol — a Logitech Harmony hub or a Sofabaton X1/X2 — finds the emulated device, and every button you press on it becomes a datapoint in ioBroker that your scripts and visualisations can react to.

It is the input counterpart to the Logitech Harmony adapter: instead of ioBroker controlling a device, a device controls ioBroker.

The official Roku mobile app does not work with this adapter. The app talks to real Rokus over Roku's proprietary, undocumented ECP-2 WebSocket channel, which this emulator does not implement. Use a Harmony hub or a Sofabaton — those speak the open protocol this adapter serves.

Requirements

  • Node.js 22 or newer
  • js-controller 7.2.2 or newer
  • admin 8.0.11 or newer
  • A remote or hub on the same local network as your ioBroker host

Setting it up

1. Create the instance

Install the adapter and create one instance. It works out of the box: the instance comes with one emulated Roku already configured, named "Roku" on port 8060.

2. Choose the network interface (usually: don't)

Leave Network interface on "all interfaces". The adapter then detects the routable address of your ioBroker host by itself and announces that.

Pick a specific address only if your ioBroker host sits on several networks and the remote is reachable on just one of them.

3. Add or edit the emulated Rokus

Each card under Emulated Roku devices is one Roku your remote can find.

  • Name — appears as the device name on the remote and as the folder in the object tree. Pick something you will recognise, for example the room.
  • ECP port — the network port this Roku answers on. 8060 is the port a real Roku uses. Each emulated Roku needs its own port; the dialog pre-selects a free one and refuses a port already taken.
  • Type
    • Player (a streaming box) offers the 16 standard navigation and playback keys.
    • TV offers those plus volume, channel and input keys and a power-off key. Choose it only if you actually want those extra buttons as triggers in ioBroker.

4. Teach your remote

Logitech Harmony: add a device in the Harmony app, choose Roku as the manufacturer, and point it at your ioBroker host. The hub finds the emulated Roku on its own and reads the port from the announcement — you do not have to enter it.

Sofabaton X1/X2: add a Roku device in the Sofabaton app while the app is on the same network. The adapter reports a current Roku version, which is what these remotes check before they accept a device.

What you get in the object tree

At instance level:

DatapointTypeMeaning
info.connectionboolean, read-onlyTrue only while every configured Roku is actually listening. If one of them cannot start — almost always because its port is already in use — the log names the device and the port, and the adapter retries that device every minute until it comes up.

For each emulated Roku, below fakeroku.0.<name>:

DatapointTypeMeaning
commandstring, read-onlyThe last command as readable text: Home, Lit_a, launch:12, search:news.
commandTypestring, read-onlyWhat kind of command it was: keypress, keydown, keyup, launch, install, input or search.
keys.<Key>boolean, read-onlyOne datapoint per remote key. A key press sets it to true for a moment and back to false; holding a key keeps it true until it is released.

Typing on the remote's keyboard (Lit_a) and app launches appear in command only — they do not get datapoints of their own.

Using it in a script

The usual way is to react to a key becoming true:

on({ id: "fakeroku.0.Living_room.keys.Play", val: true }, () => {
  // your action
});

Or watch command if you want to handle several buttons in one place:

on({ id: "fakeroku.0.Living_room.command" }, obj => {
  log("Remote sent: " + obj.state.val);
});

The key datapoints are reset to false every time the adapter starts, so a key that was left pressed when ioBroker stopped cannot block your rule afterwards. Releasing a key you are actually holding is never dropped, not even while the adapter is shedding a flood of commands — otherwise the flood protection would be the thing that left a key stuck.

Ports the adapter uses

  • TCP 8060 (one per emulated Roku, configurable) — the control protocol. Your remote sends its key presses here.
  • UDP 1900 (multicast) — device discovery, so the remote finds the emulated Rokus. This port is fixed by the standard and shared by all of them.

Only devices on your own local network are answered. A request from the internet is refused, and a discovery search from outside is ignored.

When you stop the instance, the emulated Rokus announce their departure, so a remote drops them from its list instead of sending key presses into the void for another hour.

You can run more than one instance on the same machine — give each one its own ECP ports. They share UDP 1900: the adapter opens it with address reuse, so every instance receives the discovery searches and answers for its own devices. Only if some other program holds that port exclusively does an instance start without discovery — it says so in the log, and remotes already paired with it still get through.

The adapter also runs in ioBroker's compact mode, where several adapters share one process instead of each starting their own. On a small box that saves memory and startup time. You switch it on in the instance settings; nothing here needs changing.

Troubleshooting

The remote does not find any device. Check that the hub and the ioBroker host are on the same network and that no firewall blocks UDP port 1900. On a host with several network cards, select the right one under Network interface. If discovery is unavailable the adapter says so in the log and keeps working for remotes that were already paired.

The remote finds nothing, and the log says "advertising on 172.17.x.x". That address belongs to a Docker bridge on the host, not to your home network — no remote can reach it. The adapter prefers a real network address on its own, so this only shows up when the host has nothing else to offer at that moment. Pick the correct card under Network interface and restart the instance.

The instance stays "not connected". At least one configured Roku could not start. The log names the device and its port — almost always the port is already used by something else (including another emulated Roku with the same port). Give it a free port. The adapter keeps trying such a device once a minute and says so in the log when it comes up, so a port that was still held by the previous process after a restart sorts itself out without you doing anything.

I press a button and nothing happens in ioBroker. Set the instance log level to debug for a moment. Every command the adapter applied is logged with the address it came from and, for a key, the key name (launch, input and search log what was launched or typed instead). If the line appears, the command arrived and the problem is in the script reading the datapoint.

If nothing appears, look for a warning about more than 25 commands per second first: commands dropped by that cap are not logged individually, so an overly chatty remote looks exactly like one that is not reaching the adapter at all. Without such a warning, the remote really is not getting through — check the network and the ECP port.

Play and pause do the same thing. That is the Roku protocol, not the adapter: the remote sends the same command for play and for pause, so the two cannot be told apart here.

The app buttons on my Harmony do nothing. Harmony's app buttons (Netflix, YouTube …) are bound to Harmony activities and are never sent to the device, so the adapter never sees them.

Privacy

The adapter talks only to devices on your local network. It contacts no cloud service and sends no data anywhere. Optional error reporting via Sentry is off unless you enabled diagnostics in the ioBroker system settings; it transmits an anonymous installation id and the error itself, no personal data.

Changelog

1.7.1 (2026-09-16)

  • (krobipd) Fixed: a second instance on the same host is possible again — an instance carried over from an older version still claimed the whole machine.

1.7.0 (2026-09-16)

  • (krobipd) Fixed: button datapoints keep their value and their room and function assignment when the adapter starts.
  • (krobipd) Fixed: after an emulated Roku drops out, its port is free again instead of staying blocked until ioBroker restarts.
  • (krobipd) Fixed: stopping the instance no longer leaves it reported as connected.
  • (krobipd) Fixed: a key you hold right after a short press stays pressed instead of being released early.
  • (krobipd) Fixed: the device dialog now also refuses a name that would collide with an existing device in the object tree.
  • (krobipd) Improved: after the host gets a new IP address, remotes find the emulated Rokus again without restarting the instance.
  • (krobipd) Improved: the admin now warns you when a port you enter is already used by another adapter on this host; the instance restarts once after this update.

1.6.1 (2026-09-07) — stable

  • (krobipd) Changed: installing straight from GitHub is no longer offered — the adapter is built before publishing, so it is installed from the ioBroker repository instead.

1.6.0 (2026-09-07)

  • (krobipd) Fixed: saving a device in the admin could change its identity on the network, so a paired Harmony or Sofabaton lost it.
  • (krobipd) Fixed: with the device list open twice, editing or deleting a card could hit a different emulated Roku than the one clicked.
  • (krobipd) Fixed: releasing a key was dropped while the adapter shed a flood of commands, so the key could stay pressed for half a minute.
  • (krobipd) Fixed: an ECP port still held after a restart left that device dead until you restarted the instance; it is retried every minute now.
  • (krobipd) Fixed: stopping the instance now takes the emulated Rokus out of the remote's list instead of leaving them there for up to an hour.
  • (krobipd) Fixed: an emulated Roku whose server died is no longer offered for discovery.
  • (krobipd) Fixed: a configured port no server can bind falls back to 8060 instead of leaving the device unstarted.
  • (krobipd) Changed: the device dialog refuses a reserved or colliding name right away instead of reporting it after saving.
  • (krobipd) Changed: the adapter can now run in compact mode, sharing one process with other adapters instead of claiming its own.
  • (krobipd) Changed: more than one instance may run on the same machine again; only the ports have to differ.

1.5.0 (2026-09-03)

  • (krobipd) Fixed: deleting the last emulated Roku left all of its datapoints behind for good. They are now removed whenever the configuration says a device is gone.
  • (krobipd) Fixed: on a host running Docker the adapter could announce itself under a container address no remote can reach. A real network address is preferred now.
  • (krobipd) Fixed: an emulated Roku whose server died while running left the instance showing "connected". It now reports the failure and names the device.

License

The MIT License (MIT)

Copyright (c) 2017-2023 Pmant patrickmo@gmx.de
Copyright (c) 2023-2026 iobroker-community-adapters iobroker-community-adapters@gmx.de
Copyright (c) 2026 krobi krobi@power-dreams.com

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.