jonah.id / Smart Plug
  1. 2019-03-21 — Smart Plug Intro
  2. 2019-03-22 — Smart Plug Prototype 0.1
  3. 2019-03-22 — Smart Plug Prototype 0.2
  4. 2019-03-22 — Smart Plug Prototype 0.3
  5. 2019-03-22 — Smart Plug Prototype 0.4 ⬿
  6. 2019-03-27 — Smart Plug Prototype 0.5
  7. 2019-03-29 — Smart Plug Prototype 0.6
  8. 2019-04-04 — Smart Plug Prototype 1.0
  9. 2019-06-05 — Smart Plug Prototype 2.0
  10. 2019-07-14 — Rust on Arduino
  11. 2019-07-28 — W5500 Driver for Rust Embedded-HAL on AVR
  12. 2019-07-31 — Working UDP Listener in Rust (finally)

Smart Plug Prototype 0.4

In this verison, we’ve now created a server that can open a duplex communication channel with a client. The server will send update the client on its state every 10 seconds, or any time its state changes. State is represented as a UTF-8 encoded 0 (off) or 1 (on) byte. In addition to the server updates, the client can at any point send a 0 or a 1 to the server, which will change the state of the light and update all other connected clients.

This time we’re using Netcat instead of Telnet. Our interface has gotten a bit more complex with the server, since it’s now listening for commands, not just connections. Netcat is a little newer and more modern than Telnet. The material difference in our case is that Telnet always sends \r\n line endings, but we only want \n.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
var b = require('bonescript');
var net = require('net');

var LEDS = [
  'USR0',
  'USR1',
  'USR2',
  'USR3'
];
var open_sockets = [];
var state = b.HIGH;
function setState(new_state) {
  if (new_state !== state) {
    state = new_state;
    LEDS.forEach(function (LED) {
      b.pinMode(LED, b.OUTPUT);
      b.digitalWrite(LED, state);
    });
    writeStateAllSockets();
    return true;
  } else {
    return false;
  }
}
setState(b.LOW);
function writeState(socket) {
  socket.write(state + '\n');
}
function writeStateAllSockets() {
  open_sockets.forEach(writeState);
}
setInterval(writeStateAllSockets, 10000);
var server = net.createServer(function (socket) {
  writeState(socket);  
  open_sockets.push(socket);
  socket.on('end', function () {
    open_sockets = open_sockets.filter(function (remove_socket) {
      return remove_socket !== socket;
    });
  });
  socket.on('error', function (error) {
    console.log('error', error);
  });
  socket.on('data', function (data) {
    var command_character = data.slice(0, 1);
    var ascii_signal = parseInt(command_character.toString('ascii'), 10);
    var state_changed = false;
    if (ascii_signal === 1) {
      state_changed = setState(b.HIGH);
    } else if (ascii_signal === 0) {
      state_changed = setState(b.LOW);
    } else {
      socket.write('!\n');
      return;
    }
    if (!state_changed) {
      writeState(socket);
    }
  });
});
server.listen(9999, function () {
  console.log('Ready for commands');
});

This is pretty much where the protocol needs to be for now. We have full control, and can monitor its state in real time. The next step is to connect this to a real, high-voltage application.

Next: 2019-03-27 — Smart Plug Prototype 0.5

Creative Commons License