Reverse engineering Orvibo S20 socket

I have bought Orvibo S20 (picture) smart socket. You can find them on Amazon, eBay and probably many other online shops. The socket comes with an app for Android and iOS that is used to control the socket. Unfortunately, the app is proprietary and also not available for normal computers. I wanted to have some free software solution. Also, the original app didn’t work too reliably, and of course you can’t fix it without having a code. Again, this shows why it is important to have free software…

After searching a bit I found some code on GitHub written for Ninja Blocks. It also came with some reverse engineering data (I will refer to this as the original reverse engineering later and will assume that you briefly looked at it). That file might look slightly scary initially if you are not used to that kind of stuff but actually everything is quite simple. It seems that the socket can be controlled by simply sending UDP packets over the network and listening for replies. You can even try to play a bit with netcat but of course it is not too convenient. So I decided to write my own program using Qt 5. It provides a lot of convenient functions in its QtNetwork module and also it would make it easy to write GUI if I ever decide to do so in the future. Also, I’m familiar with Qt because it is used by KDE Applications. Another reason for choosing Qt was it’s support for sockets and slots and I expected them to be useful.

As you can see in the reverse engineering file, there are commands to discover the socket, subscribe to it (which is required before doing anything else), power it on/off and read some tables (Socket Data contains information about the socket and Timing Data stores when to turn the socket on or off). They all follow similar pattern. You have to send

Magic Key+ message length + command id + rest of the message

where Magic Key is 68 64 (hexadecimals) and is used to distinguish these UDP packets from any other packets that are send over UDP port 10000. Every time you send a message the socket replies with another message confirming the action of the first message. Or the socket doesn’t reply. We are using UDP protocol for networking. So there is no guarantee that message is received and later I had to write some code to make sure packets are received. Hence, I implemented message queue and resend every command until I get a proper reply before sending another command. This finally made my program more reliable.

Writing Socket Data

I quickly managed to get some basic stuff working (for example powering it on and off) and soon I implemented most of the commands from the file with reversed engineered commands (reading Timing Table is still not completed but shouldn’t be too hard). Since I wanted to do more than that, I started Wireshark and analyzed a few more packets. I quickly learned how to write Socket Data Table too. Apparently, you send command very similar to what you receive when you request Socket Data but with different Command ID (74 6d instead of 72 74 in hexadecimals).

So to write Socket Data I send the following packet

Magic Key + message length + 74 6d + mac + mac padding + 00 00 00 00  + AA 00 BB + recordLength + record;

where

record = 01 00 /* record number = 1*/ + versionID + mac + mac padding + reversed mac + mac padding + remote password + socket name + icon + hardwareVersion + firmwareVersion + wifiFirmwareVersion + port + staticServerIP + port + domainServerName + localIP + localGatewayIP + localNetMask + dhcpNode + discoverable + timeZoneSet + timezone + countdownStatus + countdown + 00 (repeated twelve times) + 30 (repeated 30 times, note that hex 30 corresponds to 0 in ASCII);

countdownStatus is 00 ff when countdown is disabled and 01 00 when countdown is enabled.

AA 00 BB is actually table number and version flag. E.g. 04 00 01. 4 stands for table number (Socket Data is Table number 4) I don’t completely understand what is version flag, so if you know please tell me in the comments.

Then socket replies with:

Magic Key + message length + 74 6d + mac + mac padding + 01 00 00 00 00;

Now just send an already documented Socket Table packet (see: http://pastebin.com/LfUhsbcS) to update your variables.

Writing Timing Data

Writing Timing Data is exactly the same (even Command ID is still 74 6d) as writing Socket Data but you must specify 03 a a table number

Magic Key + message length + 74 6d + mac + mac padding + 00 00 00 00  + AA 00 BB + record1Length + record 1+ record2Length + record2 + record3Length + record3 + …;

record again contains the same data as what socket sends when you request timing data.

Initial pairing of the socket

The authors of the original Ninja Blocks orvibo-allone driver assume that socket was already paired using the proprietary Android/iOS application. Their original reverse engineering also contains no information how to do that. I expected that this might be a bit tricky to do because unpaired socket is not connected to the router and you have to somehow transmit your wifi configuration into the socket. I think there are at least two ways to pair that proprietary Android/iOS app implements. If you press the socket button for a few second it switches to a rapidly blinking red led mode. Then long press it again and it switches to rapidly blinking blue led and the socket creates an unencrypted wifi network (it was called WiWo-S20).

Then I created the wifi network with the same name on my laptop and tricked the proprietary app into believing that it is the socket’s wifi network. I was able to intercept the following message on UDP port 48899 (everything is in ASCII in the section, not in hex):

HF-A11ASSISTHREAD

So apparently, Orvibo S20 has HF-LPB100 Wifi chip inside. This chip can be controlled by the AT+ commands (you can find them online but I will write a brief summary here) and I was able to do initial socket configuration!

  • Switch S20 to rapidly blinking blue led more. Connect your computer to WiWo-S20 network.
  •  Send “HF-A11ASSISTHREAD” on UDP port 48899 to the broadcast address (don’t include ” in the message).
  •  S20 will reply with “IP address,MAC Address,Hostname”. The socket always replies to the same port as the source port of your message.
  • Acknowledge that you got the previous message by sending “+ok”.
  • Send “AT+WSSSID=ssid\r” where you replace ssid with your WiFi network name. \r is the carriage return (CR) symbol.
  • The socket will reply with “+ok\n\n” (\n in this case is carriage return + line feed) if everything is correct or “+ERR\n\n” if something is wrong.
  • Send your Wifi security settings: “AT+WSKEY=WPA2PSK,AES,PASSWORD\r”.  The socket will again reply with “+ok\n\n”.
  • Switch HF-A11 chip to station mode by sending “AT+WMODE=STA\r”. Again, wait for “+ok\n\n”
  • Reboot your socket with “AT+Z\r”.
  • Connect your computer back to your router. Wait until the socket boots. Now you can find it using normal discovery packet on port 10000, then change socket name, timezone, etc. with Write Socket Data packet…

I did some investigation and it seems that we need to send a slightly modified Table Data and Socket Data packets immediately after pairing to set them to default values. More information will be published later.

Another way to pair the socket from the rapidly blinking red mode. It is slighly less reliable than this method but on the other hand does not require you to disconnect from your wireless. Actually, it doesn’t require your computer to have any wireless at all.

Unfortunately, it seems that either way WPA encryption key is transferred in an insecure way, i.e. the socket is not able to use any public key cryptography. Slightly safer way to do it manually is to first change your WPA key to something temporary and pair the socket. Then use AT+ commands to change WPA password to the real one and change your router’s WPA password back.

Also, note that this socket doesn’t support WPA Enterprise. So if you would like to use it at home then create two Wifi networks: WPA-PSK for the socket and WPA-EAP for everything else (OpenWrt can do this easily).

Code

I released all code under the GNU General Public License version 3, so the code is freely available to everybody. Git repository is available at:

https://git.stikonas.eu/andrius/s20 (feel free to create an account here and fork the code)

Windows binaries

I compiled windows binaries. There is also a very limited GUI that does not yet have all the features of console app but if you prefer GUI then it might be useful.

Console 64-bit 32-bit
GUI 64-bit 32-bit

Donations

If you find this work useful then tips are very welcome. You can send Bitcoin tips to bc1qe2dfqjwgse5v6cl6rhtk352ru90t0hnve45f2c.

I was able to buy the second socket which already resulted in improved multiple socket support. Thanks for the donations!
Become a patron Donate using Liberapay Bitcoin: bc1qe2dfqjwgse5v6cl6rhtk352ru90t0hnve45f2c

Bugs

Bugs are tracked in the Gitlab issue tracker.

See also

Go code by Grayda (basic support for S20 but also supports Orvibo AllOne devices)

PHP code by Fernano Silva (supports most features of S20). See also his technical data file.

Perl code by Branislav Vartik

341 comments on “Reverse engineering Orvibo S20 socket

Comment navigation

  • Here is a script to turn device on or off (Not automatically)
    I would like help on getting script to check to see if the S20 is on or Off.
    Then send the correct command to turn the S20 On or Off.
    Then the next would to change multiple S20’s using the same script.

    Reply

    • error_reporting(E_ALL | E_STRICT);

      $ipAddress = '10.0.0.113'; //Change me
      $macAddress = 'AC:CF:23:35:62:4A'; //Change me

      $port = 10000;
      $twenties = '202020202020';
      $ma = strtolower(implode('', explode(':', $macAddress)));
      $maReverse = strtolower(implode('', array_reverse(explode(':', $macAddress))));
      $subscribe = pack('H*', '6864001e636c' . $ma . $twenties . $maReverse . $twenties);
      $on = pack('H*', '686400176463' . $ma . $twenties . '0000000001');
      $off = pack('H*', '686400176463' . $ma . $twenties . '0000000000');

      $socket = socket_create(AF_INET, SOCK_DGRAM, 0);

      socket_sendto($socket, $subscribe, strlen($subscribe), 0, $ipAddress, $port);
      sleep(1);
      socket_sendto($socket, $on, strlen($on), 0, $ipAddress, $port);
      sleep(2);
      // socket_sendto($socket, $off, strlen($off), 0, $ipAddress, $port);

      socket_close($socket);

      Reply
      • Hi, I think I got it working by looking at some PHP examples (I only know php a little).


        error_reporting(E_ALL | E_STRICT);

        $ipAddress = '10.0.0.113'; //Change me
        $macAddress = 'AC:CF:23:35:62:4A'; //Change me

        $port = 10000;
        $twenties = '202020202020';
        $ma = strtolower(implode('', explode(':', $macAddress)));
        $maReverse = strtolower(implode('', array_reverse(explode(':', $macAddress))));
        $subscribe = pack('H*', '6864001e636c' . $ma . $twenties . $maReverse . $twenties);
        $on = pack('H*', '686400176463' . $ma . $twenties . '0000000001');
        $off = pack('H*', '686400176463' . $ma . $twenties . '0000000000');

        $socket = socket_create(AF_INET, SOCK_DGRAM, 0);

        echo "Socket created \n";

        // Bind the source address
        if( !socket_bind($socket, "0.0.0.0" , $port) )
        {
        $errorcode = socket_last_error();
        $errormsg = socket_strerror($errorcode);

        die("Could not bind socket : [$errorcode] $errormsg \n");
        }

        socket_sendto($socket, $subscribe, strlen($subscribe), 0, $ipAddress, $port);

        echo "Waiting for data ... \n";
        $r = socket_recvfrom($socket, $buf, 24, 0, $ipAddress, $port);
        if( ord(substr($buf, -1)) )
        {
        echo "Socket is on\n";
        }
        else
        {
        echo "Socket is off\n";
        }
        socket_sendto($socket, $on, strlen($on), 0, $ipAddress, $port);
        sleep(2);
        // socket_sendto($socket, $off, strlen($off), 0, $ipAddress, $port);

        socket_close($socket);

        When you listen to reply to subscribe packet (24 bytes long), the last byte indicates whether it is on or off. After sending power on and poweroff packets you might also listen to reply, but it works less reliably because socket likes to send to packets in a row:
        E.g. you turn the socket on, then often socket sends first packet saying it is off and the second packet saying it is on.

        Reply
        • Hi I now have a working PHP script with toggle ON and toggle OFF thanks for your help.
          What I need to know is how to read the Table Name’s. Eg: Socket name,Time zone, Time.
          Then next step is some help on how to change socket name, Time zone etc…

          Reply
          • Basically you need to send SocketData command to read entries from the socket.

            An example is in my C++ program.

            I also first send ReadTable command to know what tables are there (but it’s not fully functional yet and SocketData is always in the 4th table anyway, so at least for now start with SocketData command).

            Then you have to capture the incoming message and parse it. It’s basically described in pastebin that I mention in my blog. Basically you can read socket name, remote password, timezone, countdown time and whether countdown is enabled/disabled. And some other less useful info but you still need to read it if you later want to modify data.

            Again, you can look at my C++ code.

            When you want to change data you just send all this data back to the socket (the one you were receiving from the socket but with a different command ID: 74 6d in hex or “tm” in ASCII (I guess this stands for table modify). Well, read that paragraph in this post, it is described in more details. And also slight differences from that pastebin file are described (e.g. their last unknown can actually be used to enable/disable countdown), and I also had to add twelve 0x00 and thirty 0x30 after countdown .

  • Hi
    I’m testing the python script with my socket and I can read the response from the subscribe command but I get no response from the tables or power on/off commands. I used wireshark in windows while running your app to get the commands and even when I send the same data I get response only from the subscribe command. Any Thoughts ? Thanks.

    Reply
    • Not really, sounds quite strange. Power on/off commands are simpler than table commands, so it is best to investigate them first. Maybe you can post a code so that I can take a look. It might be useful for others too if they have some python code to build upon.

      By the way, if you or someone else wants to use my git repo hosting for purposes of developing for S20, you can open an account at https://git.stikonas.eu/, so that it would be easier to share code. But you can of course just paste code here or somewhere else if you prefer that.

      Reply
      • Hi Andrius. I posted the code I’m testing in https://git.stikonas.eu/juandbotiva/s20python here is the output of that code. The socket doesn’t switch on when I send the ON command, and sometimes it stops responding to the TABLE command:


        Socket created
        Socket bind complete
        SUBSCRIBE package sent
        b'6864002a716100accf234b355420202020202054354b23cfac202020202020534f433030357cd97dd900'
        SUBSCRIBE package sent
        b'68640018636caccf234b3554202020202020000000000100'
        SUBSCRIBE package sent
        b'68640018636caccf234b3554202020202020000000000100'
        TABLE package sent
        b'6864002a716100accf234b355420202020202054354b23cfac202020202020534f433030357fd97dd900'
        POWER ON package sent
        b'6864002a716100accf234b355420202020202054354b23cfac202020202020534f4330303582d97dd900'

        Reply
        • Tried your program and it works very well here. Every command works, it powers on. Strange that it didn’t work for you, but I don’t think it’s your code’s fault…

          By the way, you don’t need to sent TABLE command unless you want to know name of the socket, etc… So you can just delete it from your code and you will not have a problem that it stops responding to it.

          I recently updated my own program that might fix stuck table command (no exe compiled yet) but you might need to factory reset the socket first.

          Reply
  • You were right, it works now! I was entering 192.168.1.32 instead…duh!!! Don’t know how I got that!
    Yes your C++ works fine, but I prefer your python3 because I intend to use this with RPi and Jasper for home automation (i.e. Jasper turning my heater on).
    That said, could you make a python3 script that toggles states?

    Reply
    • I don’t know python well enough and don’t have enough time. Toggling script would be more complicated because you have to listen to port 10000 (and it automatically makes program much more complicated) and parse socket replies. And I still have to add more features to my C++ program which is getting postponed too because of lack of free time.

      Reply
  • Hi Andrius thank you very much for your effort.
    I am trying to use your python3 script and I run it from raspberry pi but nothing happens. Just after 7-8 secs the script ends without powering my s20 on/off.
    I have changed my IP to 192.168.0.32 and MAC to “AC:CF:23:56:52:32” both normal and reverse without the “:”‘s….

    What is wrong?

    Regards,
    Bill

    Reply
    • Try double checking IP, mac and reverse mac. I made a few typos myself when fixing that Don Peace’s python script.

      By the way, does my C++ program work with your socket?

      Reply
  • Fixed the time zone issue, I had to use the Wiwo app from my wifes phone – and it got SYNC-ed just fine, and then the timer started working like a charm again 🙂
    Quite a weird thing.

    Reply
    • Yeah, I sometimes had some weird issues too. Glad to hear it worked. Maybe try removing Wiwo app from your phone and reinstalling it if you want to use it from your phone. Well, at some point I plan to add timer support to my app too, so check back later.

      Reply
      • Andrius, I am having a hard time getting connected “reaching” my Orvibo S20 socket from external network i.e. my phone app 4G, 3G connection or my wifi network at work.
        Do you have any idea how this could be fixed, smoothed ?
        You said the socket uses UDP port 10000. Can I speed up the process, connection if I open port 10000 UDP in my router for the socket? It really is a pain in the ass to click 20-30 times the on-off icon and sometimes it is not enough and does not turn on from remote.
        My socket is online 24/7 sitting on 192.168.1.5 IP. (HF-LPB100 ID)
        Thanks, Blaze

        Reply
        • I think forwarding UDP port 10000 in your router might help but it still might not work too reliably. I haven’t investigated remote commands (and other things have greater priority), so I can’t really tell more.

          Reply
          • I did a DHCP binding with socket mac address + UDP port forward 10000 on my router and voila : the socket powers on and off very quickly now 🙂 Many thanks for this blog where I read about the port 10000 UDP thing. I think this will ease my life turning on the socket from remote 🙂 🙂

  • I have started on making a webpage.
    I can turn device on or off so far.
    What I would like is some of your ssh commands that you use to help me fully understand.
    For example to check to see is device is on or off change name etc
    The main script I am using was the one you posted in python3
    Are you able to email them to me ?

    Reply
    • To get any feedback from the device you would have to listen to port 10000 which that python script doesn’t do. Can you execute shell commands directly and parse console output?
      Maybe something like
      (sleep 1; echo -e "q") | ./s20 | grep Power | awk '{print $8}'
      (sleep 1; echo -e "q") | ./s20 | grep Name | awk '{print $3}'
      (sleep 1; echo -e "q") | ./s20 | grep Name | awk '{print $8}'

      for current power state, name and timezone respectively. I ran this from the folder where my s20 executable is located, otherwise you have to use full path instead of ./s20.

      Reply
  • Hi Blaze, don’t know if you will see my message here but you sent an email from invalid domain and unfortunately I don’t know how to contact you and reply you back.

    Reply
    • I think your timezone is set incorrectly. Hungarian time is GMT+1 only in
      winter but now we have daylight saving time, so you should set timezone to 2.
      Can you try to see if that works? I haven’t implementing setting timers in my
      own program yet (although, I think protocol is more or less documented now),
      so you would still have to use phone for now to set the timers.

      I think after you enter factory reset mode (rapidly blinking red) and pair the
      socket again you would be in timezone 7 (which is China I think), so you have
      to change timezone after pairing it.

      Let me know if it works.

      Reply
  • Hi I run my own Debian server at home, have you had time to make the s20 to be controlled via the web?

    Reply
    • Unfortunately no. I usually just ssh into my server and use command line interface. It would be nice to have web gui too but that is outside my skills, so any contributions would be welcome. I think it can be achieved easier with Go than C++, so maybe it is possible to extend and add a webserver. But I can’t do it.

      Reply
  • Is it possible to control devices connected through Orvibo Allone as well? If so, how’s that done?

    Reply
    • Unfortunately not with my program. I have no Orvibo Allone devices, so I can’t implement it. I only have one S20 socket, so it’s already nice that my program works with any number of S20 sockets.

      Reply
  • Don Peace says:

    Perfect!
    I needed to change the IP address to 192.168.1.20 but then it all works as expected.
    Many grateful thanks

    Reply
  • Don Peace says:

    That’s a good thought – I’ve added a 1 second delay and also tried a 5 second delay but still no success.

    You mention the idea that I specifically listen for confirmation. How would I do this?

    Reply
    • Ok, you have a few more bugs:

      • Make sure you are sending those strings that are in section SEND and not RECEIVE in documentation. Basically you send a string and a socket replies with some other string on the same port number 10000. Your program does not listen to those, this is what I mentioned but it is not necessary for a simple program.
      • You are sending data as a text, not as a hex.

      Try this program. By the way, I’ve used python3 instead of python2.

      #!/usr/bin/env python3
      import socket
      import time
      mac = 'ACCF2334D04E'
      rmac = '4ED03423CFAC'
      s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
      s.connect(('192.168.1.212', 10000)) # (IP, Port) is a single variable passed to connect function
      s.send(bytes.fromhex('6864001e636C' + mac + '202020202020' + rmac + '202020202020')) # to subscribe
      time.sleep(1)
      s.send(bytes.fromhex('686400176463' + mac + '2020202020200000000001')) # to switch 'on'
      time.sleep(5) # sleep for 5 seconds
      s.send(bytes.fromhex('686400176463' + mac + '2020202020200000000000')) # to switch 'off'

      Reply
  • Don Peace says:

    Hi Andrius,
    Your information provides me with some very useful clues and ideas.

    I have the Orvibo WiFi socket working with the Android app – no problem.
    However – I want to be able to control it with my Raspberry Pi.
    My preference would be to use the Python language but if necessary another language would be ok.

    I can see the Orvibo device on my router’s GUI. Its IP address is 192.168.1.20 and its MAC address is AC:CF:23:34:D0:4E

    Following your advice and using the data gleaned from http://pastebin.com/LfUhsbcS and in particular:
    SUBSCRIBE DATA: All Commands apart from discovery require a subscription first!
    (Note: Subscription expires after a few minutes)
    SEND: UDP x.x.x.x:10000
    ASCII:
    hd0\1ecl\ac\cf#$\19\c0 \c0\19$#\cf\ac
    HEX:
    68 64 00 1e 63 6c ac cf 23 24 19 c0 20 20 20 20 20 20 c0 19 24 23 cf ac 20 20 20 20 20 20
    RECEIVE: UDP x.x.x.x:10000
    ASCII:
    hd0\18cl\ac\cf#$\19\c0 000000
    HEX:
    68 64 00 18 63 6C AC CF 23 24 19 C0 20 20 20 20 20 20 00 00 00 00 00 00
    BREAKDOWN:
    68 64 – Magic Key
    00 18 – Full Message Length = 24bytes
    63 6C – Command ID ?
    AC CF 23 24 19 C0 – Mac Address (Max Length = 12 = 24bytes)
    20 20 20 20 20 20 – Mac Address Padding (spaces)
    00 00 00 00 00 – ??? Unknown ???
    00 – Power state = off (00 = off, 01 = on)

    POWER ON DATA:
    SEND: UDP x.x.x.x:10000
    ASCII:
    hd0\17dc\ac\cf#$\19\c0 00001
    HEX:
    68 64 00 17 64 63 ac cf 23 24 19 c0 20 20 20 20 20 20 00 00 00 00 01
    RECEIVE: UDP x.x.x.x:10000
    ASCII:
    hd0\17sf\ac\cf#$\19\c0 00001
    HEX:
    68 64 00 17 73 66 AC CF 23 24 19 C0 20 20 20 20 20 20 00 00 00 00 01
    BREAKDOWN:
    68 64 – Magic Key
    00 17 – Full Message Length = 23bytes
    73 66 – Command ID ?
    AC CF 23 24 19 C0 – Mac Address (Max Length = 12 = 24bytes)
    20 20 20 20 20 20 – Mac Address Padding (spaces)
    00 00 00 00 – ??? Unknown ???
    01 – Power state = on (00 = off, 01 = on)

    I then used advice from http://adamsiembida.com/how-to-send-a-udp-packet-in-python/ , which tells me how to send UDP commands using Python, to create a python program which looks like this:

    import socket
    import time
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
    s.connect((‘192.168.1.20’, 10000)) # not sure why a double set of brackets!
    s.send(‘68640018636CACCF2334D04E202020202020000000000001’) # to subscribe
    s.send(‘686400177366ACCF2334D04E2020202020200000000001’) # to switch ‘on’
    time.sleep(5) # sleep for 5 seconds
    s.send(‘686400177366ACCF2334D04E2020202020200000000001’) # to switch ‘off’

    When I run this program nothing happens to the Orvibo. The Python program returns after approx. 5 seconds with no errors.

    Am I totally misunderstanding something?

    Reply
    • I can already see one incorrect thing in your program. You should wait a bit for subscribe confirmation. If you don’t want to specifically listen for it you should at least wait for maybe 300ms. It takes some time for the socket to process commands. Add some waiting time and try again. Don’t know if it would make it work, maybe there are other problems but let’s fix this first.

      Reply
  • Hello Andrius , im looking for someone who can create UDP packets for similar device like the one you mentioned
    would you be interested ?

    Reply
    • Most likely no… It takes some time and I only have this socket, so it would be of no use to me. I already find it difficult to finish this device :(. But I encourage you to try yourself. Wireshark is not too difficult to learn. By the way, what is that device?

      Reply
  • Patrick Menhem says:

    Hi Andrius,

    I am not sure I understand what you are trying to do. Is it an open source substitute for their wiwo app?

    Thanks

    Reply
    • I don’t plan to write an Android application (but if someone contributes code I would be glad). I only write desktop program to control those sockets. So in some sense it is free/open source equivalent of their wiwo app.

      Reply
  • And now back to not working. As described before, it seems that two menus show when it’s working, for whatever reason, and only one when s20.exe crashes.

    Sorry for the many posts.

    Reply
    • Menu is shown after each event. When a socket is discovered, menu is printed again, hence you see it twice when it is correctly discovered. If menu is shown just once, you can’t perform any actions except adding a new socket, else the program will crash. I could make a program to check for this situation but didn’t have time to do it yet.

      I’m not completely sure why socket discovery fails but looks like your firewall is blocking something. Make sure traffic over UDP port 10000 is allowed in the firewall.

      Reply
  • Okay, somehow got it working again.

    Would it be to much to ask for some more guidance on the setup of this, for people who doesn’t know anything about programming and network?

    Reply
  • Hello.

    I’ve run into troubles after installing ZoneAlarm. Whenever I choose toggle power state, s20.exe crashes. Also the “change socket name” causes s20 to crash.

    When it worked the menu would show up twice for some reason. Now it only shows one menu.

    I’ve granted acces to S20.exe in ZoneAlarm.

    Reply
  • Hi Andrius,
    I like your app. It is giving me the possibility to understand how my 3 S20 devices are working. The funny thing is that I face instability issues and your app seems to try to tell me somthing but I don’t get it.
    Here is what it gives me on the console after running the S20.exe and after waiting a couple of minutes.
    “Stop retrying: 7274accf23macmac2020202020200000000003000000000000
    Stop retrying: 636caccf23macmac202020202020c26d4b23cfac202020202020
    Stop retrying: 636caccf23macmac202020202020c26d4b23cfac202020202020
    Stop retrying: 636caccf23macmac202020202020bab84b23cfac202020202020”

    Can you figure out what this should mean?
    Thank you!

    Reply
    • That output you see is some debugging output for me (and to prevent infinite loops).

      Looks like it something unexpected happens when it tries to read table of various info from the socket. I’ve had this happening a few times for me too but I’m not completely sure what is the reason. Probably we are sending something incorrectly.

      I suggest trying to factory reset the socket and pair it again (try official app if pairing with my app results in this), it could fix the issue. If not, we could try to capture UDP packets that official app sends and compare them to my app, but this might be tricky.

      Reply
  • jimekus says:

    > Got it. It’s the Timing. If you use Redirect Input on Windows the command is send before the Connection is made and therefore the program > crashes. I put a Sleep(1000) between starting the program and sending the command and it works.

    Even so, I still have problems with the socket not initializing in time or not initializing correctly, probably due to the China server, which I wish we could do without. The whole loopy addressing model, commonly known as the cloud, seems to be there simply to overcome IPv4 router limitations. Anyway my S20Suspend.bat file does the whole operation twice, like this : –

    start “s20.exe” s20.exe
    timeout 2
    start /w SendKeys.vbs “off{enter}”
    timeout 1
    start /w SendKeys.vbs “q{enter}”
    timeout 1

    start “s20.exe” s20.exe
    timeout 2
    start /w SendKeys.vbs “off{enter}”
    timeout 1
    start /w SendKeys.vbs “q{enter}”
    start sounder.exe /loop 1 “C:\Windows\Media\Windows Hardware Remove.wav”
    timeout 1

    ——————–

    C:\Windows\SendKeys.vbs

    CreateObject(“WScript.Shell”).SendKeys Wscript.Arguments(0)

    Reply
  • Hi!

    Got it. It’s the Timing. If you use Redirect Input on Windows the command is send before the Connection is made and therefore the program crashes. I put a Sleep(1000) between starting the program and sending the command and it works.

    Thx so much for the program. Helps me 😉
    Kai

    Reply
  • Hi!
    I tried your s20.exe and it worked pretty fine when I start it and give in the Input manually. But when I use a Textfile it always gets canceled by Windows (win8.1 64 bit). The other command seem to work (at least it quits with q 😉 ).
    You got any idea what the Problem might be?

    Thx,
    Kai

    Reply
  • Hey. Thank you for this, just got it working by sheer luck 😛

    Now I need to be able to quickly toggle power state by clicking on a shortcut or a .bat file on the desktop. Any way to do that?

    Reply
    • There is no command line structure right now… On GNU/Linux it is possible control socket with input redirection. I thought that it should be possible on Windows too but some other comment here said it didn’t work but gave another solution. Try looking at older comments.

      Reply
  • Can you make a universal Windows app so that the app can also work with Windows phones?
    I would pay to have that app on the Windows store 😉

    Reply
    • Sorry, I can’t. I have neither tools (I guess Visual Studio is required) nor phone to test it. I don’t even have Windows to test the executables but at least I can test them on GNU/Linux with the help of Wine.

      But my code is licensed under GNU GPLv3 which means anybody is free to work on the code, so you can try asking/hiring someone else to do this.

      Another (less user-friendly but simpler) thing you might try is to find some app that allows sending and receiving UDP packets directly.

      Reply
  • I think just by sorting by MAC address would solve the problem, the list would be fixed as long as there is no change in the number of the connected S20.

    I already tried the GUI, but what I really need is a command line app that I will execute each time my script detects there is a loss in my home Internet connection, so it will automatically cycle the power to my ADSL modem, even if I’m not at home.

    Reply
    • Well, terminal app is more useful for me too (e.g. I can control it from this ARM server which powers the website too). That’s why I started it first and that’s why it has more features.

      I’ll try to implement sorting by MAC in the near future when I have time. If you want you can just try to add sorting via std::sort yourself (since I only have 1 device I wouldn’t really be able to test myself)(https://git.stikonas.eu/andrius/s20/src/master/server.cpp#L173)

      Reply
    • Hi Ryo. Sorry it took me so long but I now added sorting based on device name. Probably makes more sense than by mac address. Unfortunately, I can’t test it myself to see if it works. I only have 1 socket.

      Reply
  • Hi Andrius,

    nice program! However is there a way to select a device non-interactive way? I have 2 Orvibo Allinone and 1 Orvibo S20, and each time I run the s20 program (on linux) they are listed randomly; i.e. sometimes the S20 is on the top of the list, sometimes at the bottom, so I can’t use the redirection like s\n3\noff\non\nq\n because the S20 is not necessarily on the bottom of the list. Or maybe there’s a way to select a device based on the MAC address interactively?

    Reply
    • Not at the moment. Right now it is whoever replies first. I only have one S20 socket, so it’s already nice to know that I managed to write a program for any number of devices without being able to test it myself.

      I think it should be possible to implement selection based on MAC address fairly easily. Alternatively (or maybe both), it might make sense to automatically resort devices based on mac address. What do you think is better? In principle, both can be done at the same time…

      P.S. there is also some basic GUI app in git repository (only possible to turn on/off right now).

      Reply
    • I am not sure what you mean by back up. No data needs to be stored on the controlling devices. You can control the socket from as many devices as you want. But my program doesn’t work (and will never work) on iOS anyway.

      Reply
  • jimekus says:

    In order to send you a patch, is it possible for us to Skype first? Before committing you into helping me get your source code installed with an IDE and hopefully vise versa, as our fields collide, I want to ensure that there are no licensing problems or conflicts of interest. Technically, I can read most programming languages. With only a little practical Linux experience, but with 20 years of prerequisite study, I have all-in-all over 40 years of daily Commercial/Scientific experience in Assembler, FORTRAN and mainly in any form of Basic. I compiled more times than I’ve had food over the last 16 years developing my thought-processing studio in VB6. It’s called The Ingrid Thought Processor and reintroduced in 2004, it takes a month of learning and work, just to install a big background entertainment system. In 2007 the build for my off-line cloudless network was 7.3.09. As of today, v.12.1.85 is available for download.

    Reply
    • Well, I don’t have skype at all. In principle, I’ll implement countdown (because if you don’t know Qt it will still take time to learn, might be faster for me). I think there are two types of countdown. I’ve almost finished with the first one (the socket turns off some time after it is turned on), just need to fix some bugs but the other (start counting down immediately) might need more reverse engineering. More help might be necessary with this (i.e. UDP packets and their documentation for controlling it)

      The code is just GNU General Public License v3 (or any later version). So you can use copy, modify, redistribute as long as the license remains GNU GPLv3.

      Reply
  • jimekus says:

    The ‘on’ and ‘off’ commands are amazing! Thanks. Will there be any countdown resetting facilities? Ideally, I’d like to be able to let the PC go to sleep and turn off the power to its peripherals a few minutes later so that they won’t get power cycled if I resume the PC within that time.

    Reply
  • jimekus says:

    The time and zone are now correct. Before when cold booting the S20 the timezone was 08 instead of 0c and the time was since power on. Is there some cloud service which is subsequently syncing the time? Also because S20.exe knows the power state could you set an option to specifically turn it on and another to turn it off and do nothing it the current state matches the desired state. This will overcome a number of problems much easier than me trying to programmatically interpret the output. Thanks.

    Reply
    • Oh yes, I don’t automatically set the correct timezone yet. You have to do it manually. Socket sets default timezone to UTC+8 (China) and default time to 1900-01-01 00:00:00. Later, once it connects to internet it uses NTP to adjust time (but obviously not the timezone, it can’t know about your current timezone unless you tell it). I’ll try to add an option to power on or off independent of the current state. Shouldn’t be too difficult.

      Reply
  • jimekus says:

    Input redirection doesn’t work in this case. Eventually I made two files: –

    CreateObject(“WScript.Shell”).SendKeys Wscript.Arguments(0)

    (saved as SendKeys.vbs)

    and

    start “Orvibo S20” s20.exe
    timeout 1
    start /w SendKeys.vbs “p{enter}”
    timeout 1
    start /w SendKeys.vbs “q{enter}”
    start sounder.exe /loop 1 “C:\Windows\Media\Windows Hardware Remove.wav”
    timeout 1
    start G:\Downloaded\sounder.exe /loop 1 “C:\Windows\Media\Windows Hardware Remove.wav”
    timeout 3

    I use Amp WinOff to execute run the second batch file before shutdown. I couldn’t get PowerTriggers to work on shutdown/sleep, nor could I get Task Scheduler to work though both can activate the switch on resume, but I may leave that as a manual function. I notice the time and timezone aren’t working. Also is there likely to be an indicator as to the power state?

    Reply
    • Interesting. Input redirection works here on GNU/Linux. Perhaps I shouldn’t be too surprised, Windows terminal is much worse…

      Power indicator already exists. It should be saying Power: On or Power: Off on the first line. Is it not working?

      Do you see anything for Timezone: and Time: entries? Or is changing timezone not working?

      Note that changing timezone does not update time in Time:. I’m not completely sure where socket uses timezone (most likely for timers which are not implemented yet although as you can see in the blog the protocol for setting them is known). But if I set correct timezone, then official app does not complain about wrong socket time.

      Reply
  • I installed Apple’s Xcode and compiled. I get 2 entries in the “Issues” tab:

    /Orvibo/s20-master/consolereader.cpp:49: warning: unused variable ‘server’ [-Wunused-variable]
    Server *server = new Server(48899, QByteArray::fromStdString(password)); // HF-LPB100 chip can be controlled over port 48899
    ^

    /Orvibo/s20-master/server.cpp:79: warning: unused variable ‘udpSocketSend’ [-Wunused-variable]
    QUdpSocket *udpSocketSend = new QUdpSocket();
    ^

    The resultant build folder contains:

    consolereader.o
    main.o
    Makefile
    moc_server.cpp
    moc_server.o
    moc_socket.cpp
    moc_socket.o
    s20.app
    server.o
    socket.o

    Double-clicking s20.app appears to try to start the program, but there is no output. Activity Monitor shows the s20 process using 99.1 – 99.9% CPU and I have to Force Quit the process.

    If I run from within Qt Creator, I see the 10-choice list with the Enter command: prompt in the “Application Output” tab but entering e.g. p to toggle the power state has no effect.

    If I enable the option under Run Settings “Run in terminal” a new terminal window opens when selecting Run, and under these conditions I have been able to toggle the power stat, change the name and the time zone.

    Any hints or advice would be appreciated.

    Reply
    • Ignore the warnings. There are indeed some unused variables (code is far from finished). Since the app is terminal only, you have to launch it via a terminal, i.e. your last method (which if I understand correctly works fine). You should also be able to start the app via Terminal.app or something similar. Sorry, no GUI for now…

      I’m not sure why your second method doesn’t work. It’s likely that QtCreator can’t accept input in it’s output window.

      Reply
  • Could you possibly compile a Mac OS X version? QT Creator for Mac has a bug which won’t allow compile without Apple’s Xcode being installed, requiring an Apple developer account.

    Regards

    Neo

    Reply
    • Not really. I can only cross-compile for Windows because of MXE. I didn’t find any easy way to compile Mac apps on GNU/Linux. Somehow it is hard to believe that Qt creator would have such serious bug. Maybe it is just misconfigured.

      Reply
  • jimekus says:

    When Windows suspends/resumes, I would like PowerTriggers to call S20.exe from a batch file and want to send the ‘p’ as a command argument. What is your command line structure?

    Reply
    • There is no command line argument parsing right now, only interactive mode works. But you can still use input redirection s20.exe < textfile
      and type some commands to the textfile, e.g. p\nq\n (toggle power and quit) where \n should be replaced with a new line.

      Reply
  • Stephen says:

    Andrius. Thanks, that works – as in it comes up with a command list and a prompt etc. but I’ve not yet had time to try to work out exactly what it does or how to use it!

    By the way, Windows and Avast AV are both desperate to stop the download or delete the file because it does not have a reputation and is not downloaded often – bit of a Catch 22 really.

    Reply
    • 32-bit .exe file is also compressed with UPX. Maybe AV got suspicious because of that.

      Well all my code is free (as in freedom) and open, so unlike in the case of Windows or Avast, everyone can check what my app really does.

      Reply
  • Stephen says:

    Andrius, would it be possible for you to compile a Windows 32 bit version so I can try it on my old XP.
    Cheers
    Stephen

    Reply
  • I get everything correctly when i use your documentation! But not the same when i sniff the comunication between my Wiwo app on my smart phone and the socket. That’s why i’m curious how you discover the “00 00 00 00 01″ (On), if it was by sniffing the comunications between the app and the socket or other way i don’t know.

    Reply
    • Oh, maybe they changed things after some upgrade. It used to be the long way in the app too. Thanks for the info! I’ll check later but I’m quite busy for another 8 days…

      Reply
    • Sorry for taking so long to reply. I tried sniffing the app again. The reply is still the same with 00 00 00 00 01 (On). However, the app was sent me 8d 01 f6 0b instead of four 00 bytes (rest of the string was the same). I’ll try to see if it’s something recognizable… Also, Wireshark captured some other command that is unknown to me (Command ID = 68 62).
      Update: hb – 6862 – “Heartbeet” (periodic ping. Perhaps keeps socket subscribed?)

      Reply
  • Thanks for the information you disposed here.
    I’ve managed to control the S20 through the udp packets, and at the same time i’m trying to analyse the network traffic with Wireshark.
    I installed Wiwo app, but when i send an Power on/off command to the socket, i only get ” 68 64 00 17 64 63 ac cf 23 24 19 c0 20 20 20 20 20 20″ the command message is shorter than the one you proposed.
    My question is how did you figure out the last bytes of the message “00 00 00 00 01”.

    Reply
    • Strange, not sure what is happening. I always get either “00 00 00 00 01″ (On) or “00 00 00 00 00″ (Off). Are you sure you sent subscribe packet first and it successfully subscribed to the socket? Are replies to discovery and subscribe packets the same as in documentation?

      Reply
  • Stephen says:

    Thanks for that. The XP in question is actually a laptop and I can monitor the power state and detect the mains coming back on although perhaps not in a very elegant way. But even if there isn’t a practical solution to this particular problem it would still be nice to be able to control the S20 with your code from a Windows PC.

    Reply
  • Stephen says:

    I bought a couple of S20 sockets the other day and although I’m quite impressed I am a disappointed that after a power failure they power up with the switch in the “off” state which can be a bit of a problem if you are hoping the controlled device to revert to the state is was in before the power failed.

    I wondered if there was some way a PC (XP) that I have running on the same LAN could turn on the switch, if necessary, when it recovered from the power outage and came across this post.

    I can confirm Tim’s post that the s20.exe runs from the Windows command prompt and, although the process keeps running, “nothing happens”.

    Reply
    • I guess you can run some daemon on XP (provided that your XP can power itself up after power failure) that monitors the state of the socket. But that would definitely involve some programming to write such daemon. I don’t think there is an easy way…

      Ok, I’ll try to test windows executable at work on one of the windows machines. Unfortunately, if it doesn’t work, it’s likely that there isn’t much I can do right now… I can’t compile new windows binaries at the moment.

      Reply
  • Just a heads up that the windows binary you put up doesn’t work.
    It appears to be running but nothing happens.

    Reply
    • It seems to work here under Wine. Can’t test it on a real Windows system, but if it works with Wine, I don’t see why it wouldn’t work on Windows. Well, I didn’t test the initial pairing, but if the socket is paired, it should work… Could it be some Windows firewall?

      Reply
      • I get a prompt to allow or deny for the firewall (which I allowed) when I run the s20.exe in the command prompt and it returns back to the command prompt, but the process continues to run in the background. So I don’t see the menu showing the options to interact with.

        Reply
  • George says:

    My project that I am looking to do is how safe is to use the smart appliances, like our socket s20, is any way to catch the login details over the air, without having access to the local network?

    Reply
    • also i connect the wimo app on my wifi with the user name and password, and change my wifi password after the connection will the wimo ask to use the new password when i connect next time?

      Reply
    • No, you cannot scan network from outside. That would be security nightmare… You can scan it only from the inside (but e.g. I can remotely connect via SSH to my server and then scan from the inside).

      If you change your router password, wiwo app will not work. You will have to redo the pairing. In principle, it is possible to implement. You have to send a new password to the socket BEFORE you change your router password and then change the router password. Wiwo app cannot do that. I think my app can do this (or maybe very small modifications are still required).

      Reply
  • Pretty painfull that plain text wifi password, or is this just a way to open the gate for hackers …
    IoT there’s some work to be done!

    Reply
        • It will. You just need local network to pair the socket. But the password for that unconnected wifi will be transferred over plain text.

          What I did is I used WPA2-PSK for my socket and WPA2-Enterprise for my other clients. In this case even if third party knows WPA2-PSK password, it will not be able to read other traffic. But you probably need OpenWRT or other SOHO router to do this…

          Reply
          • So I could intially pair over my spare router (unsecured & without internet connection) and later use it over my regular router (connected and secured) … but then won’t it still need my WiFi password to get a new local IP adress ?
            If so, it can still exchange the info in “clear text” and eventually transmit the WiFi password over the internet …

        • Sorry, I was not completely clear. Password in clear text is not sent over the internet. It is only sent over the air, so only your neighbours or potentially somebody nearby at that time could snoop the password. So it’s not as bad as unencrypted password over the internet. I was just being picky here that security could be better…

          Once the socket is paired, you can update the wifi configuration/password while still connected to the router (and protected by WPA2) using AT+ commands over port 48899 (see my blogpost). But this definitely can’t be done with the official app. You need to send those AT+ commands yourself. So you don’t really need to use two routers, one is enough.

          The other issue is that you have to change remote password of the socket away from the default 888888…

          Reply
          • Still, every time the S20 reconnects to the router, it must send the secure WIFI password and will do it “clear text”
            or do I get that wrong …
            Can I change the 888888 from the APP?

          • Not exactly. It depends on your WiFi security settings.

            – If your wifi is not encrypted then yes, you are not safe.
            – If you use WEP, same as not encrypted, WEP doesn’t provide any security at all.
            – WPA with TKIP encryption method is a bit better but still not good enough.
            – WPA2 with AES is the one you should use. It should be safe provided your password is long enough to avoid brute force attack. WPA uses key exchange protocols that hide password from the attacker (if your password is long).

            And the same applies to any device that connects to your router (e.g. laptop too, not just socket).

            Make sure WPS (Wi-Fi Protected Setup) is disabled in your router and router only accepts connections with WPA2 and AES.

            Yes, 888888 can be changed from the app, somewhere in the settings where you can also change the name of the socket.

      • Any “Lay” solution to control the s20 (WIN exe or MAC application/script or terminal commands) … I’m a non-programming tech guy 🙁

        Reply
        • I don’t have any mac or windows computers, so I can’t compile binaries there. My program in the repository can certainly control the socket from the terminal.

          On Mac you can probably use netcat to send UDP packets directly (on port 10000) (should be possible on windows too, maybe need some other software). Michael here in the comments my have some commands ready for you. Read his comments.

          Basically, you have to send subscription packet to the socket (then the socket replies with confirmation, takes about 300ms). Then you can send Power On or Power Off packet (link with reverse engineering documentation[1] tells what has to be send. Basically, you need to know mac address of the socket and that’s it)

          [1] http://pastebin.com/LfUhsbcS

          Reply
  • I think lock in Android app just disables global discovery packets (so you have to use normal discovery packets). Knowing MAC address is sufficient to control it even when it is locked.

    But yeah, this socket wasn’t designed with good security practices in mind. It can also be seen when you pair the socket. Your wifi password is transmitted in the plain text… Why was public key cryptography invented then… Not even some basic security.

    Reply
  • Michael says:

    thank you for the good guidance and reverse engineering links!
    I’ve got my S20 just yesterday and my goal is to get it controlled easily from embedded linux SOHO routers (dd-wrt, asuswrt, etc.), so unfortunately the Qt based code is not an option – I’m too lazy to birng all the Qt stuff just for few udp packets :).

    For now, I was able to send/receive the discovery / subscription data to/from the socket using ncat (http://nmap.org/ncat):

    echo ’68 64 00 06 71 61′ | xxd -r -p | ncat -v -4u 255.255.255.255 10000

    Some of my findings at the meantime are:
    – the S20 always sends UDP reply to port 10000, regardless of udp source port of incoming packet;
    – the replies contain SOC005 at the place where SOC002 (or sometimes SOC001) is expected according to reverse eng document.
    – the “unknown” D7 is always D8 in my case.

    Hope this helps.
    thanks again!

    Reply
    • I played a bit with netcat and xxd too. But I found it a bit too limited. E.g. it would be very hard to do everything asynchronously (I use more than just QUdp, I also use QThreads, etc…).

      – I agree that S20 always sends to port 10000 regardless of the source port. However, that’s not true for AT+ commands in pairing more (that has to be sent on port 48899). Then reply port = source port.
      – I also get SOC005. That reverse engineering documentation was done last year by somebody else. Maybe there are different revisions of the socket. Obviously, I can only support my version unless somebody else can test on other revisions.
      – And that unknown is also D8 in my case. I don’t know why. Maybe it goes up every year…

      I myself have OpenWRT router too but with just 4 MB flash there is no space left at all (IPv6, and radius client for WPA2-EAP support uses up all the free space). And I was only able to fit everything when I compiled the image myself…

      Reply
      • Michael says:

        I think I solved D8/D7 mystery 🙂 This is not a standalone field, but the part of time field; and the time data is not the time since manufacture, but the time in seconds since Jan 1 1900 !! I made a quick calculation, looks very promising. However, in my case there is still ~13 days difference, so may be they are using Julian calendar?!?! Or my socket is not initialized properly – I plugged it into a wall and paired this morning, now I’m in the office and “playing” with it remotely,

        Reply
        • Thanks a lot. I will try to play again with it at some point. But this is already quite promising. Collective work of many individuals is making this socket more and more open. There are still a few things to understand but not too many.

          Reply
          • Michael says:

            I agree. The most important feature I still miss is some kind of protection – as far as I can see in docs, anyone (in my network) can control my socket by just knowing its mac address… Not so secure. However, I remember that there was something like “Lock” in Android app; will check it (and do some “wiresharking”) tonight.

        • In my case I get the date quite nicely. After subtracting from the current date:

          “1900-01-01 00:00:00.653″

          So the difference between Jan 1 1900 is just a fractions of a second (sometimes just over 1 second). So it works perfectly here. Obviously, we expect the error of about 1s here.

          Reply
  • Thank you for the code.
    I am guessing I just need to install the appropriate devel libraries and then run qmake? or make?

    Reply
    • It shouldn’t be necessary. Qt library is cross platform, so it should work on any OS (well, it should work but wasn’t tested on anything else but GNU/Linux).

      You just have to install Qt and compile my code yourself because I wouldn’t be able to provide binaries. You will have to run that program from some kind of terminal… Adding GUI shouldn’t be too hard because Qt library is already used but I would like to finish protocol part first and only work on GUI afterwards…

      Reply

Comment navigation

Leave a Reply to Steven Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Time limit is exhausted. Please reload CAPTCHA.