From b64998af9f149861b136568cfad6c9e0ef5952a8 Mon Sep 17 00:00:00 2001 From: Pascal Martin Date: Sun, 29 Nov 2020 13:10:56 -0800 Subject: [PATCH 1/2] Add "S20 only" warning --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index de9dd54..6f066e8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # orvibo -A House web service to read and control Orvibo WiFi plugs +A House web service to read and control Orvibo S20 WiFi plugs ## Overview This is a web server to give access to Ovibo WiFi electric plugs. This server can sense the current status and control the state of each plug. The web API is meant to be compatible with the House control API (e.g. the same web API as [houserelays](https://github.com/pascal-fb-martin/houserelays)). +## Warning +The Orvibo S20 is a discontinued model. Newer Orvibo models do not use the same protocol and this program is not compatible with them. ## Installation * Install the OpenSSL development package(s). * Install [echttp](https://github.com/pascal-fb-martin/echttp). From fd22f22ce445762419c33e9b26e60ae1c42f41b2 Mon Sep 17 00:00:00 2001 From: Pascal Martin Date: Sun, 29 Nov 2020 15:08:44 -0800 Subject: [PATCH 2/2] Add command line tool to setup a new device --- Makefile | 5 +- README.md | 19 +++++++ orvibosetup.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 orvibosetup.c diff --git a/Makefile b/Makefile index 5225bc1..5ffbd32 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ LIBOJS= SHARE=/usr/local/share/house -all: orvibo +all: orvibo orvibosetup clean: rm -f *.o *.a orvibo @@ -17,6 +17,9 @@ rebuild: clean all orvibo: $(OBJS) gcc -g -O -o orvibo $(OBJS) -lhouseportal -lechttp -lcrypto -lgpiod -lrt +orvibosetup: orvibosetup.o + gcc -g -O -o orvibosetup orvibosetup.o + install: if [ -e /etc/init.d/orvibo ] ; then systemctl stop orvibo ; fi mkdir -p /usr/local/bin diff --git a/README.md b/README.md index 6f066e8..1b565c0 100644 --- a/README.md +++ b/README.md @@ -32,3 +32,22 @@ Each plug must be declared in file /etc/house/orvibo.json. A typical example of } } ``` +## S20 Setup +The web service comes with a small command line tool to configure the Orvibo S20 for the local WiFi network, called orvibosetup: +``` +orvibosetup +``` +The tool first asks for the WiFi password (without echoing it) and then proceeds with the setup. The S20 must already be accessible from the computer (typically if you plan on changing your WiFi password). If it is not, follow the steps below to connect the device: +* Plug the S20 device in a nearby outlet. +* Press the button until it flashes red at high speed, then release the button. +* Press the button again until it flashes blue at high speed, then release the button. +* On your computer, connect to the WiFi SSID "WiWo-S20" (no password). + +Once the device and the computer are connected to each other, launch orvibosetup with your WiFi SSID as parameter. When prompted, enter your WiFi password. + +The S20 device should reboot: the LED turns off, then blinks red, then shows a steady red (if everything worked fine). The whole sequence may take a minute. + +Warning: if you have multiple S20 devices on the network, they will all be impacted. It is not guaranteed this will work, and some device might need to be reprogrammed. It is recommended to disconnect all other S20 devices when setting up one. + +Warning: the WiFi password is sent in the clear, possibly through an open WiFi network. + diff --git a/orvibosetup.c b/orvibosetup.c new file mode 100644 index 0000000..b9ebbff --- /dev/null +++ b/orvibosetup.c @@ -0,0 +1,147 @@ +/* orvibosetup - A simple program to setup an Orvibo S20 wiFi plug. + * + * Copyright 2020, Pascal Martin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * + * orvibosetup.c - Setup an Orvibo S20 WiFi plug or switch. + * + * SYNOPSYS: + * + * orvibosetup ssid + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static int OrviboSocket = -1; +static struct sockaddr_in OrviboBroadcast; + +static void orvibo_socket (void) { + + static int OrviboPort = 48899; + + OrviboBroadcast.sin_family = AF_INET; + OrviboBroadcast.sin_port = htons(OrviboPort); + OrviboBroadcast.sin_addr.s_addr = INADDR_BROADCAST; + + OrviboSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (OrviboSocket < 0) { + printf ("cannot open UDP socket: %s\n", strerror(errno)); + exit(1); + } + + int value = 1; + if (setsockopt(OrviboSocket, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value)) < 0) { + printf ("cannot broadcast: %s\n", strerror(errno)); + exit(1); + } + printf ("UDP socket is ready.\n"); +} + +static unsigned char hex2bin(char data) { + if (data >= '0' && data <= '9') + return data - '0'; + if (data >= 'a' && data <= 'f') + return data - 'a' + 10; + if (data >= 'A' && data <= 'F') + return data - 'A' + 10; + return 0; +} + +static char bin2hex (unsigned char d) { + d &= 0x0f; + if (d >= 0 && d <= 9) return '0' + d; + if (d >= 10 && d <= 15) return ('a' - 10) + d; + return '0'; +} + +static void orvibo_send (const char *d, const char *private) { + struct sockaddr_in a; + int sent = sendto (OrviboSocket, d, strlen(d), 0, + (struct sockaddr *)(&OrviboBroadcast), + sizeof(struct sockaddr_in)); + if (sent < 0) { + printf ("** sendto() error: %s", strerror(errno)); + exit(1); + } + if (!private) + printf ("Sending %s\n", d); + else { + char privacy[256]; + strncpy (privacy, d, sizeof(privacy)); + char *p = strstr (privacy, private); + int i = strlen(private); + while (--i>=0) *(p++) = '*'; + printf ("Sending %s\n", privacy); + } +} + +static void orvibo_receive (void) { + + char data[128]; + struct sockaddr_in addr; + int addrlen = sizeof(addr); + + int size = recvfrom (OrviboSocket, data, sizeof(data), 0, + (struct sockaddr *)(&addr), &addrlen); + + if (size <= 0) { + printf ("** recvfrom() error: %s", strerror(errno)); + return; + } + printf ("Received: %s\n", data); +} + +int main (int argc, char **argv) { + + char buffer[256]; + + if (argc != 2) { + fprintf (stderr, "Invalid parameters: need SSID.\n"); + exit(1); + } + snprintf (buffer, sizeof(buffer), "WiFi password for %s? ", argv[1]); + char *password = strdup(getpass(buffer)); + + fflush(stdout); + + orvibo_socket (); + orvibo_send ("HF-A11ASSISTHREAD", 0); + orvibo_receive(); + orvibo_send ("+ok", 0); + snprintf (buffer, sizeof(buffer), "AT+WSSSID=%s\r", argv[1]); + orvibo_send (buffer, 0); + orvibo_receive(); + snprintf (buffer, sizeof(buffer), "AT+WSKEY=WPA2PSK,AES,%s\r", password); + orvibo_send (buffer, password); + orvibo_receive(); + orvibo_send ("AT+WMODE=STA\r", 0); + orvibo_receive(); + orvibo_send ("AT+Z\r", 0); + return 0; +} +