This is the forum archive of Homey. For more information about Homey, visit the Official Homey website.

The Homey Community has been moved to https://community.athom.com.

This forum is now read-only for archive purposes.
RF-433

Creating an app to replace my 433MHz remote for dual relay controller

2»

Comments

  • Thanks for your help! 
    It's all a bit confusing for me, not having decoded any RF signals before, and definitely not tried anything like this.

    I'll try your input and see if I can get it working. 

    AFAIK the 433 generator is already deprecated, and RF Driver will be the future way of creating apps. 
    Still a bit hard for non-coders like me to get started.
  • DIYglennDIYglenn Member
    edited May 2018
    It worked! 
    Sorry, I must admit I don't quite understand where you get the numbers from. F.ex, "21", is that 22 minus the payload 6? 

    Anyways, I got further! It paired the remote, and reacts to both lock and unlock (the bell animates when I click one of the buttons). 


    Unfortunately "test" does nothing, and I don't know how to get Homey to control the relay board (does the board have to be paired with Homey...?)

    I guess this is where I'll struggle a bit further - editing the app to be more than a doorbell.

    Thank you for helping me out. I hope others in my situation can use this as well. 

    I do get an "UnhandledPromiseRejectionWarning" when clicking the "test" button.


    01.png 365.9K
    02.png 227.3K
  • JPeJPe Member
    edited May 2018
    Sorry, I didn't realize that you are using a two-button remote, I just popped in half way and forgot to read the start of this item.
    This explains the "01" and "10" at the end of the payload, these are the indicators of both buttons, and of course, these should be used. BTW there are 2 relays? Are they both switched at the same command?

    About your question " F.ex, "21", is that 22 minus the payload 6? ":  no it is  21 = 24 - 3 (the ignored bits).
    Probably the Test button is not handled right in this app ( I really have no idea ).

    Since you need more buttons to handle, maybe it's handy to use another example App, that one I used for controlling my curtains, and it's based to Brel-motors, you can find it at  https://github.com/athombv/homey-rfdriver-examples/tree/master/blinds/nl.brel-motors
    download from https://github.com/athombv/homey-rfdriver-examples
      
    In the file nl.brel-motors\drivers\MLE-25\device.js  you can make your changes:

    const data = {
    address: util.bitArrayToString(payload.slice(0, 20)),                         // >>   for you 22
    channel: util.bitArrayToString(payload.slice(20, 30)),                       // >>  (18,23) not used in your case 
    group: payload.slice(20, 30).indexOf(1) === -1,                                 // >>  (18,23) don't know where it's used?
    cmd: stateMap.get(util.bitArrayToString(payload.slice(30, 37))),  // >>  (23, 25) selects the button state
    }; 
    const commandMap = new Map([
    ['up', numberToCmdString(0x1)],                        // >>  0x1 is Hexadecimal this = 01 at the end of your payload (binairy)
    ['idle', numberToCmdString(0x2)],                      // >>  0x2 is Hexadecimal this = 10  at the end of your payload
    ['down', numberToCmdString(0x3)],                   // >>  probably handy to swap 'ídle' and 'down' texts 
    ]);
    // The bitStrings mapped to the corresponding command
    const stateMap = new Map(Array.from(commandMap.entries()).map(entry => {
    return entry.reverse(); 

    In file \nl.brel-motors\config\signals\433\brel.js you can change your signal definitions
  • JPe said:
    Sorry, I didn't realize that you are using a two-button remote, I just popped in half way and forgot to read the start of this item.
    This explains the "01" and "10" at the end of the payload, these are the indicators of both buttons, and of course, these should be used. BTW there are 2 relays? Are they both switched at the same command?

    About your question " F.ex, "21", is that 22 minus the payload 6? ":  no it is  21 = 24 - 3 (the ignored bits).
    Probably the Test button is not handled right in this app ( I really have no idea ).

    Since you need more buttons to handle, maybe it's handy to use another example App, that one I used for controlling my curtains, and it's based to Brel-motors, you can find it at  https://github.com/athombv/homey-rfdriver-examples/tree/master/blinds/nl.brel-motors
    download from https://github.com/athombv/homey-rfdriver-examples
      
    In the file nl.brel-motors\drivers\MLE-25\device.js  you can make your changes:

    const data = {
    address: util.bitArrayToString(payload.slice(0, 20)),                         // >>   for you 22
    channel: util.bitArrayToString(payload.slice(20, 30)),                       // >>  (18,23) not used in your case 
    group: payload.slice(20, 30).indexOf(1) === -1,                                 // >>  (18,23) don't know where it's used?
    cmd: stateMap.get(util.bitArrayToString(payload.slice(30, 37))),  // >>  (23, 25) selects the button state
    }; 
    const commandMap = new Map([
    ['up', numberToCmdString(0x1)],                        // >>  0x1 is Hexadecimal this = 01 at the end of your payload (binairy)
    ['idle', numberToCmdString(0x2)],                      // >>  0x2 is Hexadecimal this = 10  at the end of your payload
    ['down', numberToCmdString(0x3)],                   // >>  probably handy to swap 'ídle' and 'down' texts 
    ]);
    // The bitStrings mapped to the corresponding command
    const stateMap = new Map(Array.from(commandMap.entries()).map(entry => {
    return entry.reverse(); 

    In file \nl.brel-motors\config\signals\433\brel.js you can change your signal definitions
    No worries, I should probably have been more clear about my project. Yes, it's a box that can be set to turn on each relay individually (unlock and lock controls separate relays) momentary or toggle.

    The last setting is "latched" where it's like a typical motor controller, each button activates both relays, one OFF the other ON.  

    I'll try this example instead, thank you for helping with the example input. I'm still not sure how to calculate those numbers (18, 22, 23, 25) out from my input. 

    Too be honest, I'm not completely sure I have decoded the signal correctly, if I should start with low value or high value etc (see one of my earlier posts).

    How about all those sensitivity settings etc. from the 433 Generator?

    	"interval": 10000,
    	"sensitivity": 0.7,
    	"repetitions": 20,
    	"minimalLength": 24,
    	"maximalLength": 24
    Using RFDriver is the best solution in any case, because it's what should be used for Homey SDK 2:

    We are currently phasing out the 433 generator and its support in favor of the SDKv2 successor https://github.com/athombv/node-homey-rfdriver
    I'll scratch "my" old app, and try this instead. I was missing some tutorials on how to use the examples to create your own app. I'm not experienced enough to work out all the numbers and what to edit to make it work.

    I might create a guide when I finally get it working. I could've used a Wemos D1 Mini board + a relay board with MQTT, but I'd rather have the experience with creating an app for this controller, it's cheap and the signal is rather simple.
  • JPeJPe Member
    Great, I like the way you handle this and how eager you are to learn, lots of people just want a solution and don't care how it's working, that kind of people I don't want to spend my time on.
    To be clear, I'm not a real programmer but dit some coding in Assembler(AVR-controllers) and VisualBasic and have an electronics background. The mentioned curtain App is my first App experience with Homey and JavaScript.
    About the numbers, you are receiving 50 numbers, which are the length of the received pulses, they can vary in length a bit.
      1-low and 1-high number forming a bit, there can never be, two long pulses or two short pulses in a pair.
    so 1386 and 475  we call a word and we give that a value 0
          435   and 1328 we call a word and we give that a value 1       
    we also found a pair with a much longer value  465 and 3858 that we call "eof"
    In some signals, there is also a remarkable length at the start of the signal that we call "sof"
    "sof": [], 	
    "eof": [ 465, 3859 ],
    "words": [ [ 1396, 438 ],
    		  [  463, 1304 ]
    You received 50 values, 2 for the "sof", and 48 for data, 2 per word, so an Array of 24 words of data, but in the code, they call it bitArray.
    The position counting in Array's starts with zero, so the first bit is at position-zero, example:
    address: this.bitArrayToString(payload.slice(1, 22)),  x000011111100010000000xx 
    the Address has to be in String-format, therefore a routine providing this function is called, named "bitArrayToString" with the part "slice(1, 22)" of the payload (1,22  means including bit 1 to 22 this is including 21 but not 22), so the length of the Address is 24 - 3 = 21
    The last two bits(words) of your signal seem to be the indicators for which button has been pressed, so slice(22,24) indicates the bits 22 and 23 being the last 2 bits (and not 23,25 as I said before). If you see "payload[14]" that means copy bit 14 of the payload.
    You mentioned not to be sure about decoding starting high or low, this is not important because this definition is only handled within Homey and this same definition is used for receiving as well as for transmitting, so if you would turn it around it still will work.
    "Interval"   is the time between two repeating signals (time between "eof" and "sof" of next signal) probably in microseconds.
    "repetitions"  is the number of times the same signal is transmitted every time the Transmit command is given, fi if repetitions =  5, it will transmit:  signal - interval - signal - interval - signal - interval - signal - interval - signal.
    further https://github.com/athombv/node-homey-rfdriver gives a lot of information as I've seen
    I did not read all of that, 
    Hope this helps, don't hesitate to ask more if needed, 
    P.S. if you're in Holland, there are plans for June-6 to have a presentation for 433 development in Utrecht.
  • DIYglennDIYglenn Member
    edited May 2018
    Thank you for your explanation. I might have to read that again a few times, but I'm getting the hang of it  :D

    I've forked the example, and I'm working on a branch where I can test my settings.
    This keeps my code safe, it documents the progress for me and others, and makes it easier for people like you to help me out, rather than me posting a bunch of snippets  o:)

    There is a signal definition both in brel.js and app.json... I changed both, but maybe that's not necessary? 
    When I got everything working, I'll work on getting rid of the "brel" name and change icons etc. I'd like to document that as well, because that'll make the app suitable for the "App store". Hopefully it will once support a wide range of these relay controllers, but atm. I'm focusing on getting mine to work at all.

    Update:
    Got it installed after fixing a few comma errors (missing + trailing), but unfortunately it does not continue the wizard when I click the buttons of my remote...

    Not sure why though:
    ─────────────── Logging stdout & stderr ───────────────
    2018-05-19 21:20:20 [log] [MyApp] onInit
    2018-05-19 21:20:20 [log] [ManagerDrivers] [MLE-25] Initializing driver with log level Info and capture level Warn
    2018-05-19 21:23:17 [log] [ManagerDrivers] [MLE-25] [Info] opening pair wizard
    2018-05-19 21:23:17 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel] registered signal
    2018-05-19 21:23:36 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel ~500] payload: 011110000001110111111101
    2018-05-19 21:23:36 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel ~500] payload: 111110000001110111111101
    2018-05-19 21:23:38 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel ~500] payload: 111110000001110111111101
    2018-05-19 21:23:40 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel ~500] payload: 011110000001110111111101
    2018-05-19 21:23:43 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel ~500] payload: 011110000001110111111110
    2018-05-19 21:23:43 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel ~500] payload: 111110000001110111111110
    2018-05-19 21:23:44 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel ~500] payload: 111110000001110111111101
    2018-05-19 21:23:44 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel ~500] payload: 011110000001110111111101
    2018-05-19 21:23:45 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel ~500] payload: 011110000001110111111110
    2018-05-19 21:23:46 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel ~500] payload: 011110000001110111111101
    2018-05-19 21:23:46 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel ~500] payload: 111110000001110111111101
    2018-05-19 21:23:48 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel ~500] payload: 011110000001110111111101
    2018-05-19 21:23:50 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel ~500] payload: 011110000001110111111101
    2018-05-19 21:23:51 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel ~500] payload: 011110000001110111111101
    2018-05-19 21:23:52 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel ~500] payload: 111110000001110111111101
    2018-05-19 21:23:53 [log] [ManagerDrivers] [MLE-25] [Info] [Signal 433_brel ~500] payload: 011110000001110111111101
    
    As screenshot:


    You can see I'm alternating between the buttons. (01/10)

    But on my second try I did not alternate, and the first number is still different sometimes. Do you know why?


  • DIYglennDIYglenn Member
    edited May 2018
    I did find this:
    if (stateMap.has(util.bitArrayToString(payload.slice(30, 37)))) {
    Changed to 23,25 as the "stateMap.get" one you suggested, but unfortunately no difference... Btw, I also swap "down" and "idle" as you suggested. But what do I do with the "idle" one (which I guess I won't need?)
    const commandMap = new Map([
        ['up', numberToCmdString(0x1)],    
        ['down', numberToCmdString(0x2)],   
        ['idle', numberToCmdString(0x3)],]);

  • JPeJPe Member
    About the first bit, I don't know, that's why I suggested skipping bit-0, maybe it changes when there is a long time between the clicks.
    Slice(22,24) indicates the bits 22 and 23 being the last 2 bits (and not 23,25 as I said before)
    this is used for the choice in the Flows-Cards.
    The third line ['idle', numberToCmdString(0x3)],  is not used, you can delete it but be aware not to delete ]); at the end, It doesn't harm to leave there, because 0x3 (binary 11) will never occur.

    Lines to fix:
    address: util.bitArrayToString(payload.slice(0, 20)),  >>>>  (1,22)   x000011111100010000000xx
    data.id = `${data.address}:${data.channel}`;  >>>>   data.id = `${data.address}`;  channel not used.
    return address.concat(channel, command.split('').map(Number)); 
    this concatenates  address and channel and the command to form the signal for transmitting,
    I'm not sure exactly the format we need for the 'FirstBit' ,  
    return 'FirstBit' : address.concat(channel, command.split('').map(Number)); 
    Maybe you can find it by trying or search, (remove channel,)
  • DIYglennDIYglenn Member
    edited May 2018
    Edit: most of my comment got lost...

    Sorry, I didn’t realize you had already told me to change the values.  :s
    It does make sense, as it matches the values you suggested for the 433 generator app. 
    Tired after putting kid to bed, and not reading carefully enough I guess. 

    I will test it when I get my hands free again. 

    Regarding June 6th, I’d like to do that once, but I’m in Norway. Maybe I could combine with a family shopping/sightseeing vacation sometime.  ;)
  • DIYglennDIYglenn Member
    edited May 2018
    I've done the changes, but not the "FirstBit" section, sorry but I'm not sure what's expected there?
        static dataToPayload(data) {        if (data) {
    
                const command = commandMap.get(data.command || data.windowcoverings_state);
    
                if (command) {
                    const address = util.bitStringToBitArray(data.address);    
                const channel = util.bitStringToBitArray(data.channel);     
               return address.concat(command.split('').map(Number));  
              }  
          }   
         return null; 
       }

  • Nah, I'm stuck again. Not sure what to edit in here, and I can't seem to get the wizard to recognize my remote, even though the log shows the payload.
  • JPeJPe Member
    edited May 2018
    It's probably possible to use the variable channel in an alternative way:
    -------------------------------
    const data = {
    address: util.bitArrayToString(payload.slice(1, 22)),
    channel: util.bitArrayToString(payload.slice(7,8)),       // channel = 'bit-7'  (=0)
    cmd: stateMap.get(util.bitArrayToString(payload.slice(22, 24))),
    }
    console.log("Data.Channel: " data.channel + " " + data.cmd );   // handy usable debug help
    ------------------------------
    return channel.concat(address, command.split('').map(Number));  // swapped channel an address to get 'bit-7' at the first position.
    -------------------------------
    data.id = `${data.address}:${data.channel}`;   // >>> data.id = `${data.channel}:${data.address}`;
    ------------------------------
    const numberToCmdString = cmd => cmd.toString(2).padStart(8, '0');   // >>  padStart(2, '0');
    -------------------------------
    For editing the source code I use Notepad++ with Syntax highlighting: js
  • JPe said:
    It's probably possible to use the variable channel in an alternative way:
    -------------------------------
    const data = {
    address: util.bitArrayToString(payload.slice(1, 22)),
    channel: util.bitArrayToString(payload.slice(7,8)),       // channel = 'bit-7'  (=0)
    cmd: stateMap.get(util.bitArrayToString(payload.slice(22, 24))),
    }
    console.log("Data.Channel: " data.channel + " " + data.cmd );   // handy usable debug help
    ------------------------------
    return channel.concat(address, command.split('').map(Number));  // swapped channel an address to get 'bit-7' at the first position.
    -------------------------------
    data.id = `${data.address}:${data.channel}`;   // >>> data.id = `${data.channel}:${data.address}`;
    ------------------------------
    const numberToCmdString = cmd => cmd.toString(2).padStart(8, '0');   // >>  padStart(2, '0');
    -------------------------------
    For editing the source code I use Notepad++ with Syntax highlighting: js
    Phew, things are unfortunately a bit harder than I was expecting.

    Well, at least I can happily say that we're getting somewhere! I did the exact changes you suggested (except I added a + between "Data.Channel:" and "data.channel". (See? I'm learning!)

    This - worked!

    I could add the device and click next, where I could test the "up, idle, down" buttons. I clicked "up" twice as you can see, then clicked "down" which immediately closed my window!! Unfortunately something happened when I tried clicking the other buttons, and they didn't react, and it crashed:


  • DIYglennDIYglenn Member
    edited May 2018
    Update:
    Maybe I accidentally clicked the idle button?! 
    I tried again now, (with window shut) so that the "up" button is open, and down is closed - it works. 

    I guess this is the problem with basing on a existing app, a lot of cleanup. 

    I've tried it with a flow based on time, and it works! 

    This is awesome!!


    In theory I could just call it "finished" and be done with it. But for this to be an actual usable app, I'd like to continue the development so "Brel" is gone, and it has the correct naming, pairing wizard etc. And get rid of the idle button.


  • JPeJPe Member
    Congratulations on this result. Hope you will make a complete description of how it can be handled the easiest way with the knowledge you have now, great!
  • JPe said:
    Congratulations on this result. Hope you will make a complete description of how it can be handled the easiest way with the knowledge you have now, great!
    I definitely will! 
    A bit out of my understanding if channel is needed or not, and how you came to 7,8 for the “=0” part. 
    Is that because the signal is divided in three parts of 8? 
    I’ll do a write up when I’ve got a grasp of what’s needed and how to get it, also how to change wizard etc. 
    I’ll use GitHub as a source as well, it will document my progress. 
  • JPeJPe Member
    the 7,8 is just a random position where always stands a "0" because in your loggings, the most received messages starting with zero.
    About the first bit, I'm not so sure why it's sometimes different, that's why I suggested skipping bit-0 in the part that is used for recognizing. Maybe it changes when there is a short time between the clicks, I've seen that when the bit changes, the commands are mostly within the same second. Anyway, in the solution you now use, when the command is sent by Homey, it will always be zero. It's a workaround, probably there are other/better ways to do the same.
  • DIYglennDIYglenn Member
    edited May 2018
    Ok, so that was just a way to ignore channel?

    i believe you are right. Holding the button does not seem to create problems, but clicking fast on it will sometimes generate a different bit-0. 
    This is most likely a very simple code anyways, so it will probably work fine. 

    What I struggle a bit with understanding though, is what were to happen if I had two remotes f.ex, for different relay boards, how would they not trigger each other?
    i mean, can others use this app now (well after some cleanup)?
  • JPeJPe Member
    In your case, there is actually no "channel" in the message because there is only one device, as an example, in my case, I have a remote for max. 4 curtains so these are 4 channels.
    In your case, if you have 2 or more remotes, they should all sent out a different address (by default) and you have to add them to Homey (in the same App), one by one.
    About the line "group: payload.slice(18, 23).indexOf(1) === -1," I don't have an idea where it is used for and maybe it even isn't used? I just picked (18,23) as a random value that is in the range (0,24) of your signal. 
Sign In or Register to comment.