RF Custom App: Signal (from signal analyzer) sent but not received

For anyone that would be interested in creating an Homey app for their RF device, here is how I processed:

have a look at this:
Tuto
(Vidéo are helpful)
Then use the Homey Developper Tool to register a button of your remote.
Then you can use this tool made by someone here to make a first analysis of the signal. The goal is to identify the header, the trailer, and the data in the middle, and to compute an average signal (because of noise, each register session will result in a slightly different signal, so we need to find a average one). You also need to understand the structure of the signal and how a change in low-high signal means a 1 or a 0. See the discussion above.
Once you have your signal, you have to copy it into a dedicated file in your app, register this signal, and sent it when the app triggers.
I will not go into detail about that, it would be too long, but the documentation was quite clear about that (the only part not clear is how the signal is structured, and so how to guess the average signal), but here is the final content of my project:


And here are the more important files (keep in mind my device is a curtains type. If you have some other device type, it should have slight different content):

RF signal file (signal-rc-120.json):

{
  "sof": [
    189,
    5841
  ],
  "eof": [],
  "words": [
    [
      569,
      191
    ],
    [
      188,
      569
    ]
  ],
  "interval": 10000,
  "sensitivity": 0.5,
  "repetitions": 10,
  "minimalLength": 24,
  "maximalLength": 24,
  "cmds": {
    "up":   [0,0,0,0,1,0,1,1,0,0,1,0,0,0,1,1,0,1,1,1,1,1,0,1],
    "down": [0,0,0,0,1,0,1,1,0,0,1,0,0,0,1,1,0,1,1,1,1,0,1,1],
    "idle": [0,0,0,0,1,0,1,1,0,0,1,0,0,0,1,1,0,1,1,1,0,1,1,1]
  }
}

app.json file (into .homeycompose):

{
  "id": "com.nutyzeta.esmartcurtain",
  "version": "1.0.1",
  "compatibility": ">=5.0.0",
  "sdk": 3,
  "platforms": [
    "local"
  ],
  "name": {
    "en": "ESmart Controler",
    "fr": "Télécomande RF ESmart"
  },
  "description": {
    "en": "Simulate RF controler to open/close ESmart video projection screen.",
    "fr": "Simule la télécommande permettant d'ouvrir ou fermer l'écran de vidéoprojection ESmart."
  },
  "category": [
    "tools"
  ],
  "permissions": [
    "homey:wireless:433"
  ],
  "images": {
    "small": "/assets/images/eSmartCurtain_app_small.png",
    "large": "/assets/images/eSmartCurtain_app_large.png",
    "xlarge": "/assets/images/eSmartCurtain_app_xlarge.png"
  },
  "brandColor": "#2A5298",
  "author": {
    "name": "Ezeta"
  },
  "homepage": "https://esmart.de",
  "tags": {
    "en": [
      "esmart",
      "rf",
      "remote",
      "controler",
      "curtain",
      "video",
      "screen",
      "projection"
    ],
    "fr": [
      "esmart",
      "rf",
      "télécomande",
      "télécommande",
      "rideau",
      "vidéo",
      "écran",
      "projection",
      "projecteur"
    ]
  },
  "contributing": {
    "donate": {
      "paypal": {
        "username": "pelouas"
      }
    }
  }
}

device.js (into folder drivers/controler-rc-120)

'use strict';

const { Device } = require('homey');

class MyDevice extends Device {

  /**
   * onInit is called when the device is initialized.
   */
  async onInit() {
    this.log('MyDevice has been initialized');

    this.registerCapabilityListener("windowcoverings_state", async(value) => {
      this.log("Activated button: ", value)
      // create & register a signal using the id from your signal manifest
      const mySignal = this.homey.rf.getSignal433("signal-rc-120");

      // transmit the bits 01011001
      //await mySignal.tx([0, 1, 0, 1, 1, 0, 0, 1]);

      // transmit predefined command
      await mySignal.cmd(value); //, {"repetitions": 4});
    })
  }

  /**
   * onAdded is called when the user adds the device, called just after pairing.
   */
  async onAdded() {
    this.log('MyDevice has been added');
  }

  /**
   * onSettings is called when the user updates the device's settings.
   * @param {object} event the onSettings event data
   * @param {object} event.oldSettings The old settings object
   * @param {object} event.newSettings The new settings object
   * @param {string[]} event.changedKeys An array of keys changed since the previous version
   * @returns {Promise<string|void>} return a custom message that will be displayed
   */
  async onSettings({ oldSettings, newSettings, changedKeys }) {
    this.log('MyDevice settings where changed');
  }

  /**
   * onRenamed is called when the user updates the device's name.
   * This method can be used this to synchronise the name to the device.
   * @param {string} name The new name
   */
  async onRenamed(name) {
    this.log('MyDevice was renamed');
  }

  /**
   * onDeleted is called when the user deleted the device.
   */
  async onDeleted() {
    this.log('MyDevice has been deleted');
  }

}

module.exports = MyDevice;

in the same folder, file driver.compose.json:

{
  "name": {
    "en": "Controler RC-120",
    "fr": "Télécomande RC-120"
  },
  "class": "curtain",
  "capabilities": [
    "windowcoverings_state"
  ],
  "platforms": [
    "local"
  ],
  "connectivity": [
    "rf433"
  ],
  "images": {
    "small": "{{driverAssetsPath}}/images/esmartRc120_device_small.png",
    "large": "{{driverAssetsPath}}/images/esmartRc120_device_large.png"
  },
  "pair": [
    {
      "id": "list_devices",
      "template": "list_devices",
      "navigation": {
        "next": "add_devices"
      }
    },
    {
      "id": "add_devices",
      "template": "add_devices"
    }
  ]
}

And the driver.js file:

'use strict';

const { Driver } = require('homey');

class MyDriver extends Driver {

  /**
   * onInit is called when the driver is initialized.
   */
  async onInit() {
    this.log('MyDriver has been initialized');
  }

  /**
   * onPairListDevices is called when a user is adding a device
   * and the 'list_devices' view is called.
   * This should return an array with the data of devices that are available for pairing.
   */
  async onPairListDevices() {
    return [
      // Example device data, note that `store` is optional
      {
        name: this.homey.__("defaultDeviceName"),
        data: {
          id: 'my-esmart-rc120-controler',
        }
      }
    ];
  }

}

module.exports = MyDriver;

I recommend you create your app following the tutorial, and go have a look to this code only when you face an issue. Do not the reverse way ( copying-pasting the code as-is), because it would not work (you need to follow some steps to configure the app, add capabilities, add some dependencies, … that won’t be done if you just copy paste these files).
An additional advice, don’t forget to install the Docker app (which is needed to run the app, and was not straight forward in the tuto). And for the code editor, I installed Visual Studio.

Good luck !

3 Likes