Initial TLS support
parent
0bba170041
commit
e5629c9b04
13
README.md
13
README.md
|
@ -15,9 +15,14 @@ is directly connected on ESP-12E module.
|
||||||
Software
|
Software
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Mosquitto contained in docker is used as a broker. ESP8266 code uses [Sming
|
Mosquitto contained in docker is used as a broker. For proper TLS you need to
|
||||||
framework](https://github.com/SmingHub/Sming). Set your Wifi configuration in
|
create self-signed certificate and store its SHA-1 fingerprint in
|
||||||
`common/common_config.h` (used by both `switch` and `light`)
|
`common/common_config.h`.
|
||||||
|
|
||||||
|
ESP8266 code uses [slaff's
|
||||||
|
fork of Sming framework](https://github.com/slaff/Sming). (For axTLS support)
|
||||||
|
Set your Wifi configuration in `common/common_config.h` (used by both `switch`
|
||||||
|
and `light`)
|
||||||
|
|
||||||
|
|
||||||
Thoughts
|
Thoughts
|
||||||
|
@ -27,4 +32,4 @@ Oh my, that's slow.^W^Wquite fast, when patched properly.
|
||||||
|
|
||||||
**WARNING!** `Sming.reset();` jumps to (serial) bootloader right after flashing.
|
**WARNING!** `Sming.reset();` jumps to (serial) bootloader right after flashing.
|
||||||
This causes OTA to fail with `wdt reset`. External RESET assert is required after
|
This causes OTA to fail with `wdt reset`. External RESET assert is required after
|
||||||
flashing.
|
flashing.
|
||||||
|
|
|
@ -8,7 +8,12 @@
|
||||||
|
|
||||||
#ifndef MQTT_BROKER
|
#ifndef MQTT_BROKER
|
||||||
#define MQTT_BROKER "192.168.0.100"
|
#define MQTT_BROKER "192.168.0.100"
|
||||||
#define MQTT_PORT 1883
|
#ifdef ENABLE_SSL
|
||||||
|
#define MQTT_PORT 8883
|
||||||
|
#define SSL_FINGERPRINT { } // TODO
|
||||||
|
#else
|
||||||
|
#define MQTT_PORT 1883
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TOPIC_PREFIX "iot/"
|
#define TOPIC_PREFIX "iot/"
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
ota/*
|
||||||
|
mqtt/certs/*
|
|
@ -0,0 +1,9 @@
|
||||||
|
```
|
||||||
|
openssl req -nodes -new -x509 -days 3650 -extensions v3_ca -keyout ca.key -out ca.crt
|
||||||
|
openssl genrsa -out server.key 2048
|
||||||
|
openssl req -out server.csr -key server.key -new
|
||||||
|
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650
|
||||||
|
|
||||||
|
# Extract SHA-1
|
||||||
|
openssl x509 -in server.crt -sha1 -noout -fingerprint | sed 's/.*=/0x/g; s/:/, 0x/g'
|
||||||
|
```
|
|
@ -6,18 +6,21 @@ import sys
|
||||||
# The callback for when the client receives a CONNACK response from the server.
|
# The callback for when the client receives a CONNACK response from the server.
|
||||||
def on_connect(client, userdata, rc):
|
def on_connect(client, userdata, rc):
|
||||||
print("Connected with result code "+str(rc))
|
print("Connected with result code "+str(rc))
|
||||||
|
|
||||||
# Subscribing in on_connect() means that if we lose the connection and
|
# Subscribing in on_connect() means that if we lose the connection and
|
||||||
# reconnect then subscriptions will be renewed.
|
# reconnect then subscriptions will be renewed.
|
||||||
client.subscribe("light/status")
|
|
||||||
client.subscribe("#")
|
client.subscribe("#")
|
||||||
client.publish("iot/" + sys.argv[1] + "/" + sys.argv[2], sys.argv[3])
|
client.publish("iot/" + sys.argv[1] + "/" + sys.argv[2], sys.argv[3])
|
||||||
|
|
||||||
# The callback for when a PUBLISH message is received from the server.
|
# The callback for when a PUBLISH message is received from the server.
|
||||||
def on_message(client, userdata, msg):
|
def on_message(client, userdata, msg):
|
||||||
print(str(time.time())+" "+msg.topic+" "+str(msg.payload))
|
print(str(time.time())+" "+msg.topic+" "+str(msg.payload))
|
||||||
exit()
|
|
||||||
|
|
||||||
client = mqtt.Client("test-client-%d" % random.randint(100, 999))
|
if len(sys.argv) < 4:
|
||||||
|
print('Usage: client.py [DEVICE_ID] [ENDPOINT] [VALUE]');
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
client = mqtt.Client()
|
||||||
client.on_connect = on_connect
|
client.on_connect = on_connect
|
||||||
client.on_message = on_message
|
client.on_message = on_message
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
mosquitto:
|
mosquitto:
|
||||||
image: toke/mosquitto
|
image: toke/mosquitto
|
||||||
|
volumes:
|
||||||
|
- mqtt/config/:/mqtt/config/conf.d:ro
|
||||||
|
- mqtt/certs/:/mqtt/config/certs:ro
|
||||||
ports:
|
ports:
|
||||||
- "1883:1883"
|
- "1883:1883"
|
||||||
|
- "8883:8883"
|
||||||
|
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx
|
image: nginx
|
||||||
volumes:
|
volumes:
|
||||||
- ota:/usr/share/nginx/html
|
- ota:/usr/share/nginx/html
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
listener 8883
|
||||||
|
cafile /mqtt/config/certs/ca.crt
|
||||||
|
certfile /mqtt/config/certs/server.crt
|
||||||
|
keyfile /mqtt/config/certs/server.key
|
|
@ -49,14 +49,22 @@ void SpejsNode::keepAliveHandler() {
|
||||||
|
|
||||||
void SpejsNode::onConnected() {
|
void SpejsNode::onConnected() {
|
||||||
Serial.println("Connection successful");
|
Serial.println("Connection successful");
|
||||||
// "+deviceID+"/
|
|
||||||
mqtt.setWill(TOPIC_PREFIX + deviceID + "/state", "offline", 1, true);
|
mqtt.setWill(TOPIC_PREFIX + deviceID + "/state", "offline", 1, true);
|
||||||
|
|
||||||
|
#ifdef ENABLE_SSL
|
||||||
|
const uint8_t sha1Fingerprint[] = SSL_FINGERPRINT;
|
||||||
|
mqtt.connect("iot-" + deviceID, "", "", true);
|
||||||
|
mqtt.addSslOptions(SSL_SERVER_VERIFY_LATER);
|
||||||
|
mqtt.setSslFingerprint(sha1Fingerprint, 20);
|
||||||
|
#else
|
||||||
mqtt.connect("iot-" + deviceID);
|
mqtt.connect("iot-" + deviceID);
|
||||||
|
#endif
|
||||||
|
|
||||||
mqtt.subscribe(TOPIC_PREFIX + deviceID + "/control");
|
mqtt.subscribe(TOPIC_PREFIX + deviceID + "/control");
|
||||||
|
|
||||||
for(unsigned int i = 0 ; i < inputs.count() ; i++) {
|
for(unsigned int i = 0 ; i < inputs.count() ; i++) {
|
||||||
mqtt.subscribe(TOPIC_PREFIX + deviceID + "/" + inputs.keyAt(i));
|
mqtt.subscribe(TOPIC_PREFIX + deviceID + "/" + inputs.keyAt(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
mqtt.publish(TOPIC_PREFIX + deviceID + "/state", "online");
|
mqtt.publish(TOPIC_PREFIX + deviceID + "/state", "online");
|
||||||
|
@ -80,9 +88,10 @@ void SpejsNode::registerInput(String key, MqttStringSubscriptionCallback callbac
|
||||||
|
|
||||||
void SpejsNode::mqttCallback(String origtopic, String value) {
|
void SpejsNode::mqttCallback(String origtopic, String value) {
|
||||||
String devicePrefix = TOPIC_PREFIX + deviceID;
|
String devicePrefix = TOPIC_PREFIX + deviceID;
|
||||||
|
|
||||||
if(!origtopic.startsWith(devicePrefix)) {
|
if(!origtopic.startsWith(devicePrefix)) {
|
||||||
Serial.println("ignoring");
|
Serial.println("ignoring");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String topic = origtopic.substring(devicePrefix.length() + 1);
|
String topic = origtopic.substring(devicePrefix.length() + 1);
|
||||||
|
@ -91,24 +100,20 @@ void SpejsNode::mqttCallback(String origtopic, String value) {
|
||||||
Serial.println(value);
|
Serial.println(value);
|
||||||
|
|
||||||
if(inputs.contains(topic)) {
|
if(inputs.contains(topic)) {
|
||||||
Serial.println("dupa");
|
inputs[topic](origtopic, value);
|
||||||
inputs[topic](origtopic, value);
|
|
||||||
} else {
|
} else {
|
||||||
Serial.println("unknown topic?");
|
Serial.println("unknown topic?");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpejsNode::controlHandler(String key, String value) {
|
void SpejsNode::controlHandler(String key, String value) {
|
||||||
Serial.println("Control command: " + value);
|
Serial.println("Control command: " + value);
|
||||||
if(value == "ota") {
|
if(value == "ota") {
|
||||||
startOTA();
|
startOTA();
|
||||||
} else if(value == "restart") {
|
} else if(value == "restart") {
|
||||||
//System.restart();
|
System.restart();
|
||||||
keepaliveTimer.initializeMs(500, *[] {
|
|
||||||
System.restart();
|
|
||||||
}).start();
|
|
||||||
} else {
|
} else {
|
||||||
Serial.println("Invalid command");
|
Serial.println("Invalid command");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,9 +132,9 @@ void SpejsNode::startOTA() {
|
||||||
bootconf = rboot_get_config();
|
bootconf = rboot_get_config();
|
||||||
|
|
||||||
if (currentSlot == 0)
|
if (currentSlot == 0)
|
||||||
slot = 1;
|
slot = 1;
|
||||||
else
|
else
|
||||||
slot = 0;
|
slot = 0;
|
||||||
|
|
||||||
Serial.printf("Updating to rom %d.\r\n", slot);
|
Serial.printf("Updating to rom %d.\r\n", slot);
|
||||||
|
|
||||||
|
@ -147,11 +152,11 @@ void SpejsNode::startOTA() {
|
||||||
|
|
||||||
otaUpdater->setCallback(otaUpdateDelegate(&SpejsNode::otaUpdateCallback, this));
|
otaUpdater->setCallback(otaUpdateDelegate(&SpejsNode::otaUpdateCallback, this));
|
||||||
otaUpdater->start();
|
otaUpdater->start();
|
||||||
|
|
||||||
notify("ota", "started");
|
notify("ota", "started");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpejsNode::otaUpdateCallback(bool result) {
|
void SpejsNode::otaUpdateCallback(rBootHttpUpdate& updater, bool result) {
|
||||||
Serial.println("In callback...");
|
|
||||||
if(result == true) {
|
if(result == true) {
|
||||||
// success
|
// success
|
||||||
notify("ota", "finished");
|
notify("ota", "finished");
|
||||||
|
@ -159,18 +164,16 @@ void SpejsNode::otaUpdateCallback(bool result) {
|
||||||
uint8 slot;
|
uint8 slot;
|
||||||
|
|
||||||
if (currentSlot == 0)
|
if (currentSlot == 0)
|
||||||
slot = 1;
|
slot = 1;
|
||||||
else
|
else
|
||||||
slot = 0;
|
slot = 0;
|
||||||
|
|
||||||
// set to boot new rom and then reboot
|
// set to boot new rom and then reboot
|
||||||
Serial.printf("Firmware updated, rebooting to rom %d...\r\n", slot);
|
Serial.printf("Firmware updated, rebooting to rom %d...\r\n", slot);
|
||||||
|
|
||||||
rboot_set_temp_rom(slot);
|
rboot_set_temp_rom(slot);
|
||||||
|
|
||||||
keepaliveTimer.initializeMs(500, *[] {
|
|
||||||
System.restart();
|
System.restart();
|
||||||
}).start();
|
|
||||||
} else {
|
} else {
|
||||||
notify("ota", "failed");
|
notify("ota", "failed");
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,5 +32,5 @@ public:
|
||||||
void registerInput(String key, MqttStringSubscriptionCallback cb);
|
void registerInput(String key, MqttStringSubscriptionCallback cb);
|
||||||
void mqttCallback(String, String);
|
void mqttCallback(String, String);
|
||||||
void controlHandler(String, String);
|
void controlHandler(String, String);
|
||||||
void otaUpdateCallback(bool result);
|
void otaUpdateCallback(rBootHttpUpdate& updater, bool result);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
MODULES = app ../spejsiot
|
MODULES = app ../spejsiot
|
||||||
DISABLE_SPIFFS = 1
|
DISABLE_SPIFFS = 1
|
||||||
USER_CFLAGS = -I../common
|
USER_CFLAGS = -I../common
|
||||||
|
ENABLE_SSL = 1
|
||||||
RBOOT_ENABLED ?= 1
|
RBOOT_ENABLED = 1
|
||||||
RBOOT_BIG_FLASH ?= 1
|
RBOOT_BIG_FLASH = 1
|
||||||
|
RBOOT_RTC_ENABLED = 1
|
||||||
SPI_SIZE ?= 4M
|
SPI_SIZE ?= 4M
|
||||||
|
|
|
@ -4,7 +4,7 @@ SpejsNode node("switch");
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
node.init();
|
node.init();
|
||||||
node.registerInput("relay", *[](String value) {
|
node.registerInput("relay", *[](String key, String value) {
|
||||||
Serial.println("handler");
|
Serial.println("handler");
|
||||||
digitalWrite(5, value == "1" ? HIGH : LOW);
|
digitalWrite(5, value == "1" ? HIGH : LOW);
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,7 +5,7 @@ MEMORY
|
||||||
dport0_0_seg : org = 0x3FF00000, len = 0x10
|
dport0_0_seg : org = 0x3FF00000, len = 0x10
|
||||||
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
|
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
|
||||||
iram1_0_seg : org = 0x40100000, len = 0x8000
|
iram1_0_seg : org = 0x40100000, len = 0x8000
|
||||||
irom0_0_seg : org = 0x40202010, len = 0x42000
|
irom0_0_seg : org = 0x40202010, len = 0xF0000
|
||||||
}
|
}
|
||||||
|
|
||||||
PHDRS
|
PHDRS
|
||||||
|
@ -161,6 +161,7 @@ SECTIONS
|
||||||
*(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
|
*(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
|
||||||
out/build/app_app.a:*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
|
out/build/app_app.a:*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
|
||||||
*libsming.a:*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
|
*libsming.a:*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
|
||||||
|
*libsmingssl.a:*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
|
||||||
_irom0_text_end = ABSOLUTE(.);
|
_irom0_text_end = ABSOLUTE(.);
|
||||||
_flash_code_end = ABSOLUTE(.);
|
_flash_code_end = ABSOLUTE(.);
|
||||||
} >irom0_0_seg :irom0_0_phdr
|
} >irom0_0_seg :irom0_0_phdr
|
||||||
|
|
Loading…
Reference in New Issue