Commit 8e8f8270 authored by José Luis Conradi Hoffmann's avatar José Luis Conradi Hoffmann
Browse files

Initial import into GIT

parents
Pipeline #21 failed with stages
ESP Wifi Firmware Readme file
ESP2866 firmware to bridge EPOSMote III apps with LISHA IoT Platform. The firmware supports HTTPS, certificate-based authentication, and EDUROAM connection.
The code was meant to be flashed into an ESP2866 through Arduino IDE
(more info at: https://software.intel.com/en-us/get-started-arduino-install).
For the code to be supported by the Arduino IDE, ESP2866 library is needed (more info at: https://github.com/esp8266/Arduino).
Step-by-Step Code Configuration:
1. Look for the "Configuration Section" inside the code file (esp_wifi_firmware.ino)
2. Modify the variables as needed
2.1. DEBUG(x) x --> Enable Debug messages, remove "x" to disable Debug messages
2.2. IF WPA2 wifi conection is needed, set WPA2 to 1.
2.2.1. Finish the WPA2 configuration setting the login info (ssid, password, user, pass).
2.3. IF WPA2 wifi will not be used, set WPA2 to 0.
2.3.1. Finish the Wifi configuration setting the login info (ssid and password of wifi NOT WPA2).
2.4. Set the HTTP configuration (host address, host port, api_attach and api_put).
2.4.1. Config the acceptable retries to host connection (0 if unlimited).
2.4.2. Config the time out for a HTTP response from host (0 if ignored).
2.4.3. IF a certificate will be used to validate the connection with the server, set SSL_VERIFICATION to 1, else 0.
2.4.3.1. Fill the client_cert and private_key information to fully configure SSL certificate verification.
2.4.4. IF certificates are NOT being used and a Default credential will be used for every post set DEFAULT Credentials to 1 and configure client_credentials_json as needed.
2.5. Interactions by DEFAULT are done as follows: "++post(\"your smartdata here\")\0x255\0x255" for an API PUT and "--post("your series here")\0x255\0x255" for an API ATTACH, the -- and ++ and \0x255\0x255 can be modified as needed through PUT_CONTROL_CHAR, ATTACH_CONTROL_CAR and END_CONTROL_CHAR. Also the methods loop() and parse_post() configure the serial parsing state machine and can be modified as aswell.
How to flash:
- Required a FTDI connected both to the computer and the ESP
- ESP PIN configuration (FLASH boot mode):
-- FTDI TX in ESP8266 RX
-- FTDI RX in ESP8266 TX
-- FTDI GROUND in ESP8266 GROUND and GPIO 0
-- FTDI VCC in ESP8266 VCC, RESET and CH_EN
- To boot ESP8266 in RUN Mode, use the same configuration and disconnect ground from GPIO 0
Arduino IDE Recommended Configuration:
- Arduino IDE version used: 1.8.11
- Tools Menu:
-- Board: "Generic ESP8266 Module"
-- Upload Speed: "115200"
-- CPU Frequency: "160 MHz"
-- Crystal Frequency: "26 MHz"
-- Flash Size: "512K (no SPIFFS)"
-- Flash Mode: "DOUT (compatible)"
-- Flash Frequency: "40MHz"
-- Reset Method: "ck"
-- Debug Port: "Disabled"
-- Debug Level: "None"
-- lwIP Variant: "v2 Lower Memory"
-- VTables: "Flash"
-- Exceptions: "Disabled"
-- Builtin Led: "2"
-- Erase Flash: "Only Sketch"
-- SSL Support: "All SSL ciphers(most compatible)"
-- Programmer: "AVRISP mkII"
#include <ESP8266WiFi.h>
#include <time.h>
extern "C" {
#include "user_interface.h"
#include "c_types.h"
#include "wpa2_enterprise.h"
}
/* ================================================================ */
/* =================== Configuration Section ================== */
/* ================================================================ */
#define DEBUG(x) x // Enable debug messages (i.e. DEBUG(x) x)
// remove "x" to disable (i.e. DEBUG(x) )
#define WPA2 1 // Will use WPA2 for wifi connection
// Set to 0 to not use WPA2
#if WPA2 == 1
const char *ssid = "wifi_name"; // WPA2 WIFI SSID e.g. "eduroam"
const char *password = ""; // WPA2 Password, leave as empty string
const char *user = "my_user_name"; // WPA2 User name
const char *pass = "my_password"; // WPA2 User password
#else
const char *ssid = "wifi_name"; // WIFI SSID e.g. "LISHA"
const char *password = "wifi_password"; // WIFI Password
#endif
// HTTP POST configuration // Deafault Value
const char * host = "iot.lisha.ufsc.br"; // "iot.lisha.ufsc.br"
const uint16_t port = 443; // 443
const char * api_attach = "/api/attach.php"; // "/api/attach.php"
const char * api_put = "/api/put.php"; // "/api/put.php"
#define CONNECTION_TRIES_LIMIT 10 // Number of connection attempts to host
// Set to 0 to while true
#define RESPONSE_TIME_OUT 0 // Wait for response timeout
// Set to 0 to ignore response
#define SSL_VERIFICATION 1 // Enable SSL certificate communication
// Set to 0 in order to use credentials
#define DEFAULT_CREDENTIALS 0 // IF no SSL certificate and Setted to 1
// will use credentials configured bellow
// Set to 0 in order to use credentials
// from each message
#if SSL_VERIFICATION == 1 // Used for certificate login
// cert.pem file content
// command to read file: openssl x509 -in cert.pem -text
static const char client_cert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
INSERT CLIENT CERITFICATE HERE
-----END CERTIFICATE-----
)EOF";
// cert.key file content
// command to read file: openssl rsa -in cert.key -text
static const char private_key[] PROGMEM = R"EOF(
-----BEGIN RSA PRIVATE KEY-----
INSERT CLIENT PRIVATE KEY HERE
)EOF";
BearSSL::PrivateKey client_key(private_key);
BearSSL::X509List client_crt(client_cert);
#elif DEFAULT_CREDENTIALS == 1 // Used for credential dafault login
const char *client_credentials_json = ",\"credentials\":{\"domain\":\"my_domain\",\"username\":\"my_user\",\"password\":\"my_password\"}";
#endif
// The following configuration is related to the message parsing, chage as needed.
// Also, functions like loop() and parse_post() can be modified as needed
// they only represent a state machine for the serial parsing
#define PUT_CONTROL_CHAR '+' // Every put will begin with ++post
#define ATTACH_CONTROL_CHAR '-' // Every attach will begin with --post
#define END_CONTROL_CHAR 255 // Every message should end with char(255)
/* ================================================================ */
/* ================= END of Configuration Section ================= */
/* ================================================================ */
BearSSL::WiFiClientSecure *client;
BearSSL::Session session;
char buff[256];
char slen[6];
#if RESPONSE_TIME_OUT > 0
unsigned short print_crc16(char * ptr, int size) {
unsigned short crc = 0;
while(--size >= 0) {
crc ^= (unsigned short)(*ptr++) << 8;
int i = 8;
do{
if(crc & 0x8000)
crc = (crc << 1) ^ 0x1021;
else
crc = crc << 1;
} while(--i);
}
Serial.printf("%05i", crc);
return crc;
}
char json_msg[128];
int msg_count;
void timeout_print_awnser() {
uint32_t to = millis() + RESPONSE_TIME_OUT;
int status = 0;
char ans_msg[128];
int msg_count = 0;
memset(ans_msg, 0, 128);
if (client->connected()) {
do {
char tmp[128];
memset(tmp, 0, 128);
int rlen = client->read((uint8_t*)tmp, sizeof(tmp) - 1);
yield();
DEBUG(Serial.println(tmp));
if (rlen < 0) {
break;
}
int i = 0;
while (i < rlen) {
if (tmp[i] == '\r' && (status == 0 || status == 2)) {
status++;
}
else if (tmp[i] == '\n' && (status == 1 || status == 3)) {
status++;
}
else if (tmp[i] == '{' && status == 4) {
ans_msg[msg_count++] = tmp[i];
status++;
}
else if (tmp[i] != '}' && status == 5) {
ans_msg[msg_count++] = tmp[i];
}
else if (tmp[i] == '}' && status == 5) {
ans_msg[msg_count++] = tmp[i];
status++;
break;
}
else {
status = 0;
}
i++;
}
} while (millis() < to);
}
DEBUG(Serial.println (client->getLastSSLError()));
DEBUG(Serial.println("\n-------"));
if (status == 6) {
memcpy(json_msg, ans_msg, 128);
Serial.print(json_msg);
print_crc16(json_msg, msg_count);
DEBUG(Serial.println());
DEBUG(Serial.println(msg_count));
}
DEBUG(Serial.printf("-------\n\n"));
}
#endif
bool connect_client() {
if (client == 0) {
client = new BearSSL::WiFiClientSecure;
client->setSession(&session);
client->setInsecure();
#if SSL_VERIFICATION == 1
client->setClientRSACert(&client_crt, &client_key);
#endif
}
if (client->connected())
return true;
#if CONNECTION_TRIES_LIMIT > 0
for (int tries = 0; tries < CONNECTION_TRIES_LIMIT; tries++) {
#else
while(true) {
#endif
client->connect(host, port);
if (client->connected())
return true;
}
return false;
}
void post(bool is_put) {
if (!connect_client())
return;
DEBUG(Serial.printf("Connected! RAM: %d\n-------\n",ESP.getFreeHeap()));
uint16_t len = strlen(buff)+2; //buff + 2"{"
#if DEFAULT_CREDENTIALS == 1 && SSL_VERIFICATION == 0
len += strlen(client_credentials_json);
#endif
DEBUG(Serial.printf("LEN: %d", len));
itoa(len, slen, 10);
client->write("POST ");
if(is_put)
client->write(api_put);
else
client->write(api_attach);
client->write(" HTTP/1.0\r\nHost: iot.lisha.ufsc.br\r\nContent-Type: application/json");
client->write("\r\nContent-Length: ");
client->write(slen);
client->write("\r\n\r\n{");
client->write(buff);
#if DEFAULT_CREDENTIALS == 1 && SSL_VERIFICATION == 0
client->write(client_credentials_json);
#endif
client->write("}");
DEBUG(Serial.println("Req Ready!"));
client->flush();
DEBUG(Serial.println("Req Send!"));
#if RESPONSE_TIME_OUT > 0
timeout_print_awnser();
#endif
client->stop();
}
void parse_post(bool is_put) {
char c;
int i = 0;
int status = 0;
while (true) {
if (Serial.available() > 0) {
c = Serial.read();
if (c == '\r' || c == '\n')
continue;
DEBUG(Serial.print(c));
if (status == 0 && c == 'o')
status++;
else if (status == 1 && c == 's')
status++;
else if (status == 2 && c == 't')
status++;
else if (status == 3 && c == '(')
status++;
else if (status == 4 && c == '\'')
status++;
else if (status == 5 && c != '\'') {
buff[i++] = c;
}
else if (status == 5 && c == '\'') {
buff[i++] = '\0';
status++;
}
else if (status == 6 && c == ')')
status++;
else if (status == 7 && (c == (char) END_CONTROL_CHAR))
status++;
else if (status == 8 && (c == (char) END_CONTROL_CHAR)) {
DEBUG(Serial.print(buff));
post(is_put);
break;
} else {
DEBUG(Serial.println("err_not_post"));
return;
}
if (i > 254) {
DEBUG(Serial.println("err_too_long"));
return;
}
}
}
}
void setup() {
Serial.begin(115200);
DEBUG(Serial.println());
DEBUG(Serial.println());
DEBUG(Serial.print("\r\n>>> "));
// We start by connecting to a WiFi network
WiFi.mode(WIFI_STA);
#if WPA2 == 1
wifi_station_set_wpa2_enterprise_auth(1);
wifi_station_set_enterprise_identity((u8 *)user, strlen(user));
wifi_station_set_enterprise_username((u8 *)user, strlen(user));
wifi_station_set_enterprise_password((u8 *)pass, strlen(pass));
wifi_station_set_enterprise_new_password((u8 *)pass, strlen(pass));
#endif
DEBUG(Serial.print("Connecting to "));
DEBUG(Serial.println(ssid));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
DEBUG(Serial.print("."));
}
DEBUG(Serial.println());
DEBUG(Serial.println("WiFi connected"));
DEBUG(Serial.println("IP address: "));
DEBUG(Serial.println(WiFi.localIP()));
DEBUG(Serial.printf("%02x:%02x:%02x:%02x:%02x:%02x RSSI:%d\r\n",
WiFi.BSSID()[0],
WiFi.BSSID()[1],
WiFi.BSSID()[2],
WiFi.BSSID()[3],
WiFi.BSSID()[4],
WiFi.BSSID()[5],
WiFi.RSSI()
));
#if 0
while (true) {
DEBUG(Serial.printf("RSSI:%d\r\n", WiFi.RSSI()));
delay(1000);
}
#endif
}
void ignore_message() {
char c[2];
int status = 0;
while(true) {
if (Serial.available() > 0){
c[status++] = Serial.read();
if (status == 2) {
if (c[0] == (char) END_CONTROL_CHAR && c[1] == (char) END_CONTROL_CHAR) {
return;
} else {
status = 1;
c[0] = c[1];
}
}
}
}
}
void loop() {
char c[3];
int status = 0;
DEBUG(Serial.print("\r\n>>> "));
while (true) {
if (Serial.available() > 0) {
c[status] = Serial.read();
if (c[status] == '\r' || c[status] == '\n')
continue;
if (status < 2) { // read ++p or --p, p is ignored here
status++;
} else {
DEBUG(Serial.print(c[0]));
DEBUG(Serial.print(c[1]));
if (c[0] == PUT_CONTROL_CHAR && c[1] == PUT_CONTROL_CHAR) {
parse_post(true);
break;
}
else if (c[0] == ATTACH_CONTROL_CHAR && c[1] == ATTACH_CONTROL_CHAR) {
parse_post(false);
break;
}
else {
ignore_message();
}
}
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment