Browse Source

Split main code file into modules

fastled
Xose Pérez 8 years ago
parent
commit
183b326b5f
16 changed files with 1378 additions and 1273 deletions
  1. +1
    -1
      code/deploy
  2. +13
    -1
      code/platformio.ini
  3. +28
    -0
      code/src/button.ino
  4. +84
    -0
      code/src/defaults.h
  5. +73
    -0
      code/src/dht.ino
  6. +85
    -0
      code/src/emon.ino
  7. +0
    -1270
      code/src/main.cpp
  8. +228
    -0
      code/src/main.ino
  9. +161
    -0
      code/src/mqtt.ino
  10. +88
    -0
      code/src/nofuss.ino
  11. +64
    -0
      code/src/ota.ino
  12. +62
    -0
      code/src/relay.ino
  13. +85
    -0
      code/src/rf.ino
  14. +1
    -1
      code/src/version.h
  15. +243
    -0
      code/src/webserver.ino
  16. +162
    -0
      code/src/wifi.ino

+ 1
- 1
code/deploy View File

@ -60,4 +60,4 @@ if valid_ip $ip; then
exit 3
fi
echo platformio run -vv -e $device --target upload --upload-port $ip
platformio run -vv -e $device --target upload --upload-port $ip

+ 13
- 1
code/platformio.ini View File

@ -81,7 +81,7 @@ board = esp01_1m
lib_install = 89,64,19
topic = /home/cellar/washer/ip
build_flags = -Wl,-Tesp8266.flash.1m256.ld
build_flags = -D SONOFF -D DEBUG -D ENABLE_POWER -D ENABLE_DHT
build_flags = -D SONOFF -D DEBUG -D ENABLE_EMON -D ENABLE_DHT
upload_speed = 115200
upload_port = "192.168.1.114"
upload_flags = --auth=fibonacci --port 8266
@ -97,3 +97,15 @@ build_flags = -D SONOFF -D DEBUG
upload_speed = 115200
upload_port = "192.168.1.114"
upload_flags = --auth=fibonacci --port 8266
[env:living-lamp-device]
platform = espressif
framework = arduino
board = esp01_1m
lib_install = 89,64,19
topic = /home/living/lamp/ip
build_flags = -Wl,-Tesp8266.flash.1m256.ld
build_flags = -D SONOFF -D DEBUG -D RF
upload_speed = 115200
upload_port = "192.168.1.114"
upload_flags = --auth=fibonacci --port 8266

+ 28
- 0
code/src/button.ino View File

@ -0,0 +1,28 @@
/*
ESPurna
BUTTON MODULE
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
*/
#include <DebounceEvent.h>
DebounceEvent button1 = false;
// -----------------------------------------------------------------------------
// BUTTON
// -----------------------------------------------------------------------------
void buttonSetup() {
button1 = DebounceEvent(BUTTON_PIN);
}
void buttonLoop() {
if (button1.loop()) {
if (button1.getEvent() == EVENT_SINGLE_CLICK) toggleRelay();
if (button1.getEvent() == EVENT_LONG_CLICK) wifiAP();
if (button1.getEvent() == EVENT_DOUBLE_CLICK) ESP.reset();
}
}

+ 84
- 0
code/src/defaults.h View File

@ -0,0 +1,84 @@
// Managed from platformio.ini
//#define DEBUG
//#define ESPURNA
//#define SONOFF
//#define SLAMPHER
//#define S20
//#define NODEMCUV2
//#define ENABLE_NOFUSS 1
//#define ENABLE_EMON 1
//#define ENABLE_RF 1
//#define ENABLE_DHT 1
#define BUTTON_PIN 0
#define RELAY_PIN 12
#ifdef ESPURNA
#define MANUFACTURER "TINKERMAN"
#define DEVICE "ESPURNA"
#define LED_PIN 13
#endif
#ifdef SONOFF
#define MANUFACTURER "ITEAD"
#define DEVICE "SONOFF"
#define LED_PIN 13
#endif
#ifdef SLAMPHER
#define MANUFACTURER "ITEAD"
#define DEVICE "SLAMPHER"
#define LED_PIN 13
#endif
#ifdef S20
#define MANUFACTURER "ITEAD"
#define DEVICE "S20"
#define LED_PIN 13
#endif
#ifdef NODEMCUV2
#define MANUFACTURER "NODEMCU"
#define DEVICE "LOLIN"
#define LED_PIN 16
#endif
#define AP_PASS "fibonacci"
#define OTA_PASS "fibonacci"
#define OTA_PORT 8266
#define BUFFER_SIZE 1024
#define STATUS_UPDATE_INTERVAL 30000
#define HEARTBEAT_INTERVAL 60000
#define FS_VERSION_FILE "/fsversion"
#define WIFI_RECONNECT_INTERVAL 300000
#define RF_PIN 14
#define DHT_PIN 14
#define DHT_UPDATE_INTERVAL 300000
#define DHT_TYPE DHT22
#define DHT_TIMING 11
#define MQTT_RECONNECT_DELAY 10000
#define MQTT_RETAIN true
#define MQTT_STATUS_TOPIC ""
#define MQTT_IP_TOPIC "/ip"
#define MQTT_VERSION_TOPIC "/version"
#define MQTT_FSVERSION_TOPIC "/fsversion"
#define MQTT_HEARTBEAT_TOPIC "/heartbeat"
#define MQTT_POWER_TOPIC "/power"
#define MQTT_TEMPERATURE_TOPIC "/temperature"
#define MQTT_HUMIDITY_TOPIC "/humidity"
#define EMON_CURRENT_PIN 0
#define EMON_SAMPLES 1000
#define EMON_INTERVAL 10000
#define EMON_MEASUREMENTS 6
#define EMON_ADC_BITS 10
#define EMON_REFERENCE_VOLTAGE 1.0
#define EMON_CURRENT_PRECISION 1
#define EMON_CURRENT_OFFSET 0.25

+ 73
- 0
code/src/dht.ino View File

@ -0,0 +1,73 @@
/*
ESPurna
DHT MODULE
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
*/
#if ENABLE_DHT
#include "DHT.h"
DHT dht(DHT_PIN, DHT_TYPE, DHT_TIMING);
double temperature;
double humidity;
// -----------------------------------------------------------------------------
// DHT
// -----------------------------------------------------------------------------
double getTemperature() {
return temperature;
}
double getHumidity() {
return humidity;
}
void dhtSetup() {
dht.begin();
}
void dhtLoop() {
static unsigned long last_check = 0;
if (!mqttConnected()) return;
if ((last_check > 0) && ((millis() - last_check) < DHT_UPDATE_INTERVAL)) return;
last_check = millis();
char buffer[10];
temperature = dht.readTemperature();
if (isnan(temperature)) {
#ifdef DEBUG
Serial.println(F("[DHT] Error reading temperature"));
#endif
} else {
dtostrf(temperature, 4, 1, buffer);
mqttSend((char *) MQTT_TEMPERATURE_TOPIC, buffer);
#ifdef DEBUG
Serial.print(F("[DHT] Temperature: "));
Serial.println(temperature);
#endif
}
humidity = dht.readHumidity();
if (isnan(humidity)) {
#ifdef DEBUG
Serial.println(F("[DHT] Error reading humidity"));
#endif
} else {
dtostrf(humidity, 4, 1, buffer);
mqttSend((char *) MQTT_HUMIDITY_TOPIC, buffer);
#ifdef DEBUG
Serial.print(F("[DHT] Humidity: "));
Serial.println(humidity);
#endif
}
}
#endif

+ 85
- 0
code/src/emon.ino View File

@ -0,0 +1,85 @@
/*
ESPurna
EMON MODULE
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
*/
#if ENABLE_EMON
#include <EmonLiteESP.h>
EmonLiteESP power;
double current;
// -----------------------------------------------------------------------------
// EMON
// -----------------------------------------------------------------------------
double getCurrent() {
return current;
}
unsigned int currentCallback() {
return analogRead(EMON_CURRENT_PIN);
}
void powerMonitorSetup() {
power.initCurrent(currentCallback, EMON_ADC_BITS, EMON_REFERENCE_VOLTAGE, config.pwCurrentRatio.toFloat());
power.setPrecision(EMON_CURRENT_PRECISION);
}
void powerMonitorLoop() {
static unsigned long next_measurement = millis();
static byte measurements = 0;
static double max = 0;
static double min = 0;
static double sum = 0;
if (!mqttConnected()) return;
if (millis() > next_measurement) {
// Safety check: do not read current if relay is OFF
if (!digitalRead(RELAY_PIN)) {
current = 0;
} else {
current = power.getCurrent(EMON_SAMPLES);
current -= EMON_CURRENT_OFFSET;
if (current < 0) current = 0;
}
if (measurements == 0) {
max = min = current;
} else {
if (current > max) max = current;
if (current < min) min = current;
}
sum += current;
++measurements;
#ifdef DEBUG
Serial.print(F("[ENERGY] Power now: "));
Serial.print(int(current * config.pwMainsVoltage.toFloat()));
Serial.println(F("W"));
#endif
if (measurements == EMON_MEASUREMENTS) {
char buffer[8];
double power = (sum - max - min) * config.pwMainsVoltage.toFloat() / (measurements - 2);
sprintf(buffer, "%d", int(power));
mqttSend((char *) MQTT_POWER_TOPIC, buffer);
sum = 0;
measurements = 0;
}
next_measurement += EMON_INTERVAL;
}
}
#endif

+ 0
- 1270
code/src/main.cpp
File diff suppressed because it is too large
View File


+ 228
- 0
code/src/main.ino View File

@ -0,0 +1,228 @@
/*
ESPurna
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
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 3 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, see <http://www.gnu.org/licenses/>.
*/
extern "C" {
#include "user_interface.h"
}
#include <Arduino.h>
#include "version.h"
#include "defaults.h"
#include "FS.h"
#include "Config.h"
// -----------------------------------------------------------------------------
// Methods
// -----------------------------------------------------------------------------
void getCompileTime(char * buffer) {
int day, month, year, hour, minute, second;
// parse date
String tmp = String(__DATE__);
day = tmp.substring(4,6).toInt();
year = tmp.substring(7).toInt();
tmp = tmp.substring(0,3);
if (tmp.equals("Jan")) month = 1;
if (tmp.equals("Feb")) month = 2;
if (tmp.equals("Mar")) month = 3;
if (tmp.equals("Apr")) month = 4;
if (tmp.equals("May")) month = 5;
if (tmp.equals("Jun")) month = 6;
if (tmp.equals("Jul")) month = 7;
if (tmp.equals("Aug")) month = 8;
if (tmp.equals("Sep")) month = 9;
if (tmp.equals("Oct")) month = 10;
if (tmp.equals("Nov")) month = 11;
if (tmp.equals("Dec")) month = 12;
// parse time
tmp = String(__TIME__);
hour = tmp.substring(0,2).toInt();
minute = tmp.substring(3,5).toInt();
second = tmp.substring(6,8).toInt();
sprintf(buffer, "%d%02d%02d%02d%02d%02d", year, month, day, hour, minute, second);
buffer[14] = 0;
}
String getIdentifier() {
char identifier[20];
sprintf(identifier, "%s_%06X", DEVICE, ESP.getChipId());
return String(identifier);
}
void blink(unsigned long delayOff, unsigned long delayOn) {
static unsigned long next = millis();
static bool status = HIGH;
if (next < millis()) {
status = !status;
digitalWrite(LED_PIN, status);
next += ((status) ? delayOff : delayOn);
}
}
void showStatus() {
if (wifiConnected()) {
blink(5000, 500);
} else {
blink(500, 500);
}
}
void hardwareSetup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
SPIFFS.begin();
}
void getFSVersion(char * buffer) {
File h = SPIFFS.open(FS_VERSION_FILE, "r");
if (!h) {
#ifdef DEBUG
Serial.println(F("[SPIFFS] Could not open file system version file."));
#endif
strcpy(buffer, APP_VERSION);
return;
}
size_t size = h.size();
h.readBytes(buffer, size - 1);
h.close();
}
void hardwareLoop() {
showStatus();
// Heartbeat
static unsigned long last_heartbeat = 0;
if (millis() - last_heartbeat > HEARTBEAT_INTERVAL) {
last_heartbeat = millis();
mqttSend((char *) MQTT_HEARTBEAT_TOPIC, (char *) "1");
#ifdef DEBUG
Serial.print(F("[BEAT] Free heap: "));
Serial.println(ESP.getFreeHeap());
#endif
}
}
// -----------------------------------------------------------------------------
// Booting
// -----------------------------------------------------------------------------
void welcome() {
char buffer[BUFFER_SIZE];
getCompileTime(buffer);
Serial.println();
Serial.println();
Serial.print(APP_NAME);
Serial.print(F(" "));
Serial.print(APP_VERSION);
Serial.print(F(" built "));
Serial.println(buffer);
Serial.println(APP_AUTHOR);
Serial.println(APP_WEBSITE);
Serial.println();
Serial.print(F("Device: "));
Serial.println(getIdentifier());
Serial.print(F("Last reset reason: "));
Serial.println(ESP.getResetReason());
Serial.print(F("Memory size: "));
Serial.print(ESP.getFlashChipSize());
Serial.println(F(" bytes"));
Serial.print(F("Free heap: "));
Serial.print(ESP.getFreeHeap());
Serial.println(F(" bytes"));
FSInfo fs_info;
if (SPIFFS.info(fs_info)) {
Serial.print(F("File system total size: "));
Serial.print(fs_info.totalBytes);
Serial.println(F(" bytes"));
Serial.print(F("File system used size : "));
Serial.print(fs_info.usedBytes);
Serial.println(F(" bytes"));
}
Serial.println();
}
void setup() {
hardwareSetup();
relaySetup();
buttonSetup();
delay(1000);
welcome();
config.load();
// At the moment I am overriding any possible hostname stored in EEPROM
// with the generated one until I have a way to change them from the
// configuration interface
config.hostname = getIdentifier();
wifi_station_set_hostname((char *) config.hostname.c_str());
wifiSetup();
otaSetup();
mqttSetup();
webServerSetup();
#if ENABLE_NOFUSS
nofussSetup();
#endif
#if ENABLE_RF
rfSetup();
#endif
#if ENABLE_DHT
dhtSetup();
#endif
#if ENABLE_EMON
powerMonitorSetup();
#endif
}
void loop() {
wifiLoop();
hardwareLoop();
buttonLoop();
otaLoop();
mqttLoop();
webServerLoop();
#if ENABLE_NOFUSS
nofussLoop();
#endif
#if ENABLE_RF
rfLoop();
#endif
#if ENABLE_DHT
dhtLoop();
#endif
#if ENABLE_EMON
powerMonitorLoop();
#endif
delay(1);
}

+ 161
- 0
code/src/mqtt.ino View File

@ -0,0 +1,161 @@
/*
ESPurna
MQTT MODULE
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
*/
#include <WiFiClient.h>
#include <PubSubClient.h>
WiFiClient client;
PubSubClient mqtt(client);
String mqttTopic;
bool isCallbackMessage = false;
// -----------------------------------------------------------------------------
// MQTT
// -----------------------------------------------------------------------------
bool mqttConnected() {
return mqtt.connected();
}
void buildTopics() {
// Replace identifier
mqttTopic = config.mqttTopic;
mqttTopic.replace("{identifier}", config.hostname);
}
void mqttSend(char * topic, char * message) {
if (!mqtt.connected()) return;
if (isCallbackMessage) return;
String path = mqttTopic + String(topic);
#ifdef DEBUG
Serial.print(F("[MQTT] Sending "));
Serial.print(path);
Serial.print(F(" "));
Serial.println(message);
#endif
mqtt.publish(path.c_str(), message, MQTT_RETAIN);
}
void mqttCallback(char* topic, byte* payload, unsigned int length) {
#ifdef DEBUG
Serial.print(F("[MQTT] Received "));
Serial.print(topic);
Serial.print(F(" "));
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
#endif
// Action to perform
if ((char)payload[0] == '0') {
isCallbackMessage = true;
switchRelayOff();
}
if ((char)payload[0] == '1') {
isCallbackMessage = true;
switchRelayOn();
}
if ((char)payload[0] == '2') {
toggleRelay();
}
isCallbackMessage = false;
}
void mqttConnect() {
if (!mqtt.connected() && (config.mqttServer.length()>0)) {
mqtt.setServer((const char *) config.mqttServer.c_str(), config.mqttPort.toInt());
#ifdef DEBUG
Serial.print(F("[MQTT] Connecting to broker at "));
Serial.print(config.mqttServer);
#endif
if (config.mqttUser.length() > 0) {
#ifdef DEBUG
Serial.print(F(" as user "));
Serial.print(config.mqttUser);
Serial.print(F(": "));
#endif
mqtt.connect(
config.hostname.c_str(),
(const char *) config.mqttUser.c_str(),
(const char *) config.mqttPassword.c_str()
);
} else {
#ifdef DEBUG
Serial.print(F(" anonymously: "));
#endif
mqtt.connect(config.hostname.c_str());
}
if (mqtt.connected()) {
#ifdef DEBUG
Serial.println(F("connected!"));
#endif
buildTopics();
// Say hello and report our IP and VERSION
mqttSend((char *) MQTT_IP_TOPIC, (char *) getIP().c_str());
mqttSend((char *) MQTT_VERSION_TOPIC, (char *) APP_VERSION);
char buffer[10];
getFSVersion(buffer);
mqttSend((char *) MQTT_FSVERSION_TOPIC, buffer);
// Publish current relay status
mqttSend((char *) MQTT_STATUS_TOPIC, (char *) (digitalRead(RELAY_PIN) ? "1" : "0"));
// Subscribe to topic
#ifdef DEBUG
Serial.print(F("[MQTT] Subscribing to "));
Serial.println(mqttTopic);
#endif
mqtt.subscribe(mqttTopic.c_str());
} else {
#ifdef DEBUG
Serial.print(F("failed, rc="));
Serial.println(mqtt.state());
#endif
}
}
}
void mqttSetup() {
mqtt.setCallback(mqttCallback);
}
void mqttLoop() {
static unsigned long timeout = millis();
if (wifiConnected()) {
if (!mqtt.connected()) {
if (timeout < millis()) {
mqttConnect();
timeout = millis() + MQTT_RECONNECT_DELAY;
}
}
if (mqtt.connected()) mqtt.loop();
}
}

+ 88
- 0
code/src/nofuss.ino View File

@ -0,0 +1,88 @@
/*
ESPurna
NOFUSS MODULE
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
*/
#if ENABLE_NOFUSS
#include "NoFUSSClient.h"
// -----------------------------------------------------------------------------
// NOFUSS
// -----------------------------------------------------------------------------
void nofussSetup() {
NoFUSSClient.setServer(config.nofussServer);
NoFUSSClient.setDevice(DEVICE);
NoFUSSClient.setVersion(APP_VERSION);
NoFUSSClient.onMessage([](nofuss_t code) {
if (code == NOFUSS_START) {
Serial.println(F("[NoFUSS] Start"));
}
if (code == NOFUSS_UPTODATE) {
Serial.println(F("[NoFUSS] Already in the last version"));
}
if (code == NOFUSS_PARSE_ERROR) {
Serial.println(F("[NoFUSS] Error parsing server response"));
}
if (code == NOFUSS_UPDATING) {
Serial.println(F("[NoFUSS] Updating"));
Serial.print( F(" New version: "));
Serial.println(NoFUSSClient.getNewVersion());
Serial.print( F(" Firmware: "));
Serial.println(NoFUSSClient.getNewFirmware());
Serial.print( F(" File System: "));
Serial.println(NoFUSSClient.getNewFileSystem());
}
if (code == NOFUSS_FILESYSTEM_UPDATE_ERROR) {
Serial.print(F("[NoFUSS] File System Update Error: "));
Serial.println(NoFUSSClient.getErrorString());
}
if (code == NOFUSS_FILESYSTEM_UPDATED) {
Serial.println(F("[NoFUSS] File System Updated"));
}
if (code == NOFUSS_FIRMWARE_UPDATE_ERROR) {
Serial.print(F("[NoFUSS] Firmware Update Error: "));
Serial.println(NoFUSSClient.getErrorString());
}
if (code == NOFUSS_FIRMWARE_UPDATED) {
Serial.println(F("[NoFUSS] Firmware Updated"));
}
if (code == NOFUSS_RESET) {
Serial.println(F("[NoFUSS] Resetting board"));
}
if (code == NOFUSS_END) {
Serial.println(F("[NoFUSS] End"));
}
});
}
void nofussLoop() {
static unsigned long last_check = 0;
if (!wifiConnected()) return;
if ((last_check > 0) && ((millis() - last_check) < config.nofussInterval.toInt())) return;
last_check = millis();
NoFUSSClient.handle();
}
#endif

+ 64
- 0
code/src/ota.ino View File

@ -0,0 +1,64 @@
/*
ESPurna
OTA MODULE
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
*/
#include <ArduinoJson.h>
#include "ArduinoOTA.h"
// -----------------------------------------------------------------------------
// OTA
// -----------------------------------------------------------------------------
void otaSetup() {
ArduinoOTA.setPort(OTA_PORT);
ArduinoOTA.setHostname(config.hostname.c_str());
ArduinoOTA.setPassword((const char *) OTA_PASS);
ArduinoOTA.onStart([]() {
#if ENABLE_RF
rfEnable(false);
#endif
#if DEBUG
Serial.println(F("[OTA] Start"));
#endif
});
ArduinoOTA.onEnd([]() {
#if DEBUG
Serial.println(F("[OTA] End"));
#endif
#if ENABLE_RF
rfEnable(true);
#endif
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
#if DEBUG
Serial.printf("[OTA] Progress: %u%%\r", (progress / (total / 100)));
#endif
});
ArduinoOTA.onError([](ota_error_t error) {
#if DEBUG
Serial.printf("[OTA] Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println(F("[OTA] Auth Failed"));
else if (error == OTA_BEGIN_ERROR) Serial.println(F("[OTA] Begin Failed"));
else if (error == OTA_CONNECT_ERROR) Serial.println(F("[OTA] Connect Failed"));
else if (error == OTA_RECEIVE_ERROR) Serial.println(F("[OTA] Receive Failed"));
else if (error == OTA_END_ERROR) Serial.println(F("[OTA] End Failed"));
#endif
});
ArduinoOTA.begin();
}
void otaLoop() {
ArduinoOTA.handle();
}

+ 62
- 0
code/src/relay.ino View File

@ -0,0 +1,62 @@
/*
ESPurna
RELAY MODULE
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
*/
#include <EEPROM.h>
// -----------------------------------------------------------------------------
// RELAY
// -----------------------------------------------------------------------------
void switchRelayOn() {
if (!digitalRead(RELAY_PIN)) {
#ifdef DEBUG
Serial.println(F("[RELAY] ON"));
#endif
digitalWrite(RELAY_PIN, HIGH);
EEPROM.write(0, 1);
EEPROM.commit();
mqttSend((char *) MQTT_STATUS_TOPIC, (char *) "1");
}
}
void switchRelayOff() {
if (digitalRead(RELAY_PIN)) {
#ifdef DEBUG
Serial.println(F("[RELAY] OFF"));
#endif
digitalWrite(RELAY_PIN, LOW);
EEPROM.write(0, 0);
EEPROM.commit();
mqttSend((char *) MQTT_STATUS_TOPIC, (char *) "0");
}
}
void toggleRelay() {
if (digitalRead(RELAY_PIN)) {
switchRelayOff();
} else {
switchRelayOn();
}
}
void relaySetup() {
pinMode(RELAY_PIN, OUTPUT);
EEPROM.begin(4096);
EEPROM.read(0) == 1 ? switchRelayOn() : switchRelayOff();
}

+ 85
- 0
code/src/rf.ino View File

@ -0,0 +1,85 @@
/*
ESPurna
RF MODULE
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
*/
#if ENABLE_RF
#include <RemoteReceiver.h>
unsigned long rfCode = 0;
unsigned long rfCodeON = 0;
unsigned long rfCodeOFF = 0;
// -----------------------------------------------------------------------------
// RF
// -----------------------------------------------------------------------------
void rfEnable(bool enable) {
if (enable) {
RemoteReceiver::enable();
} else {
RemoteReceiver::disable();
}
}
void rfLoop() {
if (rfCode == 0) return;
#ifdef DEBUG
Serial.print(F("[RF] Received code: "));
Serial.println(rfCode);
#endif
if (rfCode == rfCodeON) switchRelayOn();
if (rfCode == rfCodeOFF) switchRelayOff();
rfCode = 0;
}
void rfBuildCodes() {
unsigned long code = 0;
// channel
unsigned int channel = config.rfChannel.toInt();
for (byte i = 0; i < 5; i++) {
code *= 3;
if (channel & 1) code += 1;
channel >>= 1;
}
// device
unsigned int device = config.rfDevice.toInt();
for (byte i = 0; i < 5; i++) {
code *= 3;
if (device != i) code += 2;
}
// status
code *= 9;
rfCodeOFF = code + 2;
rfCodeON = code + 6;
#ifdef DEBUG
Serial.print(F("[RF] Code ON: "));
Serial.println(rfCodeON);
Serial.print(F("[RF] Code OFF: "));
Serial.println(rfCodeOFF);
#endif
}
void rfCallback(unsigned long code, unsigned int period) {
rfCode = code;
}
void rfSetup() {
pinMode(RF_PIN, INPUT_PULLUP);
rfBuildCodes();
RemoteReceiver::init(RF_PIN, 3, rfCallback);
RemoteReceiver::enable();
}
#endif

+ 1
- 1
code/src/version.h View File

@ -1,4 +1,4 @@
#define APP_NAME "Espurna"
#define APP_VERSION "0.9.6"
#define APP_VERSION "0.9.7"
#define APP_AUTHOR "xose.perez@gmail.com"
#define APP_WEBSITE "http://tinkerman.cat"

+ 243
- 0
code/src/webserver.ino View File

@ -0,0 +1,243 @@
/*
ESPurna
WEBSERVER MODULE
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
*/
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include "FS.h"
ESP8266WebServer server(80);
// -----------------------------------------------------------------------------
// WEBSERVER
// -----------------------------------------------------------------------------
String getContentType(String filename) {
if (server.hasArg("download")) return "application/octet-stream";
else if (filename.endsWith(".htm")) return "text/html";
else if (filename.endsWith(".html")) return "text/html";
else if (filename.endsWith(".css")) return "text/css";
else if (filename.endsWith(".js")) return "application/javascript";
else if (filename.endsWith(".png")) return "image/png";
else if (filename.endsWith(".gif")) return "image/gif";
else if (filename.endsWith(".jpg")) return "image/jpeg";
else if (filename.endsWith(".ico")) return "image/x-icon";
else if (filename.endsWith(".xml")) return "text/xml";
else if (filename.endsWith(".pdf")) return "application/x-pdf";
else if (filename.endsWith(".zip")) return "application/x-zip";
else if (filename.endsWith(".gz")) return "application/x-gzip";
return "text/plain";
}
void handleRelayOn() {
#ifdef DEBUG
Serial.println(F("[WEBSERVER] Request: /relay/on"));
#endif
switchRelayOn();
server.send(200, "text/plain", "ON");
}
void handleRelayOff() {
#ifdef DEBUG
Serial.println(F("[WEBSERVER] Request: /relay/off"));
#endif
switchRelayOff();
server.send(200, "text/plain", "OFF");
}
bool handleFileRead(String path) {
#ifdef DEBUG
Serial.print(F("[WEBSERVER] Request: "));
Serial.println(path);
#endif
if (path.endsWith("/")) path += "index.html";
String contentType = getContentType(path);
String pathWithGz = path + ".gz";
if (SPIFFS.exists(pathWithGz)) path = pathWithGz;
if (SPIFFS.exists(path)) {
File file = SPIFFS.open(path, "r");
size_t sent = server.streamFile(file, contentType);
size_t contentLength = file.size();
file.close();
return true;
}
return false;
}
void handleInit() {
#ifdef DEBUG
Serial.println("[WEBSERVER] Request: /init");
#endif
char buffer[64];
char built[16];
getCompileTime(built);
sprintf(buffer, "%s %s built %s", APP_NAME, APP_VERSION, built);
StaticJsonBuffer<1024> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["appname"] = String(buffer);
root["manufacturer"] = String(MANUFACTURER);
root["device"] = String(DEVICE);
root["hostname"] = config.hostname;
root["network"] = (WiFi.status() == WL_CONNECTED) ? WiFi.SSID() : "ACCESS POINT";
root["ip"] = (WiFi.status() == WL_CONNECTED) ? WiFi.localIP().toString() : WiFi.softAPIP().toString();
root["updateInterval"] = STATUS_UPDATE_INTERVAL;
root["ssid0"] = config.ssid[0];
root["pass0"] = config.pass[0];
root["ssid1"] = config.ssid[1];
root["pass1"] = config.pass[1];
root["ssid2"] = config.ssid[2];
root["pass2"] = config.pass[2];
root["mqttServer"] = config.mqttServer;
root["mqttPort"] = config.mqttPort;
root["mqttUser"] = config.mqttUser;
root["mqttPassword"] = config.mqttPassword;
root["mqttTopic"] = config.mqttTopic;
#if ENABLE_RF
root["rfChannel"] = config.rfChannel;
root["rfDevice"] = config.rfDevice;
#endif
#if ENABLE_EMON
root["pwMainsVoltage"] = config.pwMainsVoltage;
root["pwCurrentRatio"] = config.pwCurrentRatio;
#endif
String output;
root.printTo(output);
server.send(200, "text/json", output);
}
void handleStatus() {
// Update reconnection timeout to avoid disconnecting the web client
resetConnectionTimeout();
#ifdef DEBUG
//Serial.println("[WEBSERVER] Request: /status");
#endif
StaticJsonBuffer<256> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["relay"] = digitalRead(RELAY_PIN) ? 1: 0;
root["mqtt"] = mqtt.connected() ? 1: 0;
#if ENABLE_EMON
root["power"] = getCurrent() * config.pwMainsVoltage.toFloat();
#endif
#if ENABLE_DHT
root["temperature"] = getTemperature();
root["humidity"] = getHumidity();
#endif
String output;
root.printTo(output);
server.send(200, "text/json", output);
}
void handleSave() {
#ifdef DEBUG
Serial.println(F("[WEBSERVER] Request: /save"));
#endif
if (server.hasArg("status")) {
if (server.arg("status") == "1") {
switchRelayOn();
} else {
switchRelayOff();
}
}
if (server.hasArg("ssid0")) config.ssid[0] = server.arg("ssid0");
if (server.hasArg("pass0")) config.pass[0] = server.arg("pass0");
if (server.hasArg("ssid1")) config.ssid[1] = server.arg("ssid1");
if (server.hasArg("pass1")) config.pass[1] = server.arg("pass1");
if (server.hasArg("ssid2")) config.ssid[2] = server.arg("ssid2");
if (server.hasArg("pass2")) config.pass[2] = server.arg("pass2");
if (server.hasArg("mqttServer")) config.mqttServer = server.arg("mqttServer");
if (server.hasArg("mqttPort")) config.mqttPort = server.arg("mqttPort");
if (server.hasArg("mqttUser")) config.mqttUser = server.arg("mqttUser");
if (server.hasArg("mqttPassword")) config.mqttPassword = server.arg("mqttPassword");
if (server.hasArg("mqttTopic")) config.mqttTopic = server.arg("mqttTopic");
#if ENABLE_RF
if (server.hasArg("rfChannel")) config.rfChannel = server.arg("rfChannel");
if (server.hasArg("rfDevice")) config.rfDevice = server.arg("rfDevice");
#endif
#if ENABLE_EMON
if (server.hasArg("pwMainsVoltage")) config.pwMainsVoltage = server.arg("pwMainsVoltage");
if (server.hasArg("pwCurrentRatio")) config.pwCurrentRatio = server.arg("pwCurrentRatio");
#endif
server.send(202, "text/json", "{}");
config.save();
#if ENABLE_RF
rfBuildCodes();
#endif
#if ENABLE_EMON
power.setCurrentRatio(config.pwCurrentRatio.toFloat());
#endif
// Disconnect from current WIFI network, wifiLoop will take care of the reconnection
wifiDisconnect();
}
void webServerSetup() {
// Relay control
server.on("/relay/on", HTTP_GET, handleRelayOn);
server.on("/relay/off", HTTP_GET, handleRelayOff);
// Configuration page
server.on("/init", HTTP_GET, handleInit);
server.on("/status", HTTP_GET, handleStatus);
server.on("/save", HTTP_POST, handleSave);
// Anything else
server.onNotFound([]() {
// Hidden files
#ifndef DEBUG
if (server.uri().startsWith("/.")) {
server.send(403, "text/plain", "Forbidden");
return;
}
#endif
// Existing files in SPIFFS
if (!handleFileRead(server.uri())) {
server.send(404, "text/plain", "NotFound");
return;
}
});
// Run server
server.begin();
}
void webServerLoop() {
server.handleClient();
}

+ 162
- 0
code/src/wifi.ino View File

@ -0,0 +1,162 @@
/*
ESPurna
WIFI MODULE
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
*/
#include "JustWifi.h"
JustWifi jw;
unsigned long wifiLastConnectionTime = 0;
// -----------------------------------------------------------------------------
// WIFI
// -----------------------------------------------------------------------------
String getIP() {
return jw.getIP();
}
String getNetwork() {
return jw.getNetwork();
}
void wifiDisconnect() {
jw.disconnect();
}
void resetConnectionTimeout() {
wifiLastConnectionTime = millis();
}
bool wifiConnected() {
return jw.connected();
}
void wifiSetup() {
// Message callbacks
jw.onMessage([](justwifi_messages_t code, char * parameter) {
// Disconnect from MQTT server if no WIFI
if (code != MESSAGE_CONNECTED) {
if (mqtt.connected()) mqtt.disconnect();
}
#if DEBUG
if (code == MESSAGE_AUTO_NOSSID) {
Serial.println("[WIFI] No information about the last successful network");
}
if (code == MESSAGE_AUTO_CONNECTING) {
Serial.print("[WIFI] Connecting to last successful network: ");
Serial.println(parameter);
}
if (code == MESSAGE_AUTO_FAILED) {
Serial.println("[WIFI] Could not connect to last successful network");
}
if (code == MESSAGE_CONNECTING) {
Serial.print("[WIFI] Connecting to ");
Serial.println(parameter);
}
if (code == MESSAGE_CONNECT_WAITING) {
//
}
if (code == MESSAGE_CONNECT_FAILED) {
Serial.print("[WIFI] Could not connect to ");
Serial.println(parameter);
}
if (code == MESSAGE_CONNECTED) {
Serial.print("[WIFI] Connected to ");
Serial.print(jw.getNetwork());
Serial.print(" with IP ");
Serial.println(jw.getIP());
}
if (code == MESSAGE_DISCONNECTED) {
Serial.println("[WIFI] Disconnected");
}
if (code == MESSAGE_ACCESSPOINT_CREATING) {
Serial.println("[WIFI] Creating access point");
}
if (code == MESSAGE_ACCESSPOINT_CREATED) {
Serial.print("[WIFI] Access point created with SSID ");
Serial.print(jw.getNetwork());
Serial.print(" and IP ");
Serial.println(jw.getIP());
}
if (code == MESSAGE_ACCESSPOINT_FAILED) {
Serial.println("[WIFI] Could not create access point");
}
#endif
});
}
bool wifiAP() {
//jw.disconnect();
return jw.startAP((char *) config.hostname.c_str(), (char *) AP_PASS);
}
void wifiConnect() {
resetConnectionTimeout();
//WiFi.printDiag(Serial);
// Set networks
jw.cleanNetworks();
jw.addNetwork((char *) config.ssid[0].c_str(), (char *) config.pass[0].c_str());
jw.addNetwork((char *) config.ssid[1].c_str(), (char *) config.pass[1].c_str());
jw.addNetwork((char *) config.ssid[2].c_str(), (char *) config.pass[2].c_str());
// Connecting
if (!jw.autoConnect()) {
if (!jw.connect()) {
if (!wifiAP()) {
#if DEBUG
Serial.println("[WIFI] Could not start any wifi interface!");
#endif
}
}
}
}
void wifiLoop() {
jw.loop();
// Check disconnection
if (!jw.connected()) {
// If we are in AP mode try to reconnect every WIFI_RECONNECT_INTERVAL
// wifiLastConnectionTime gets updated upon every connect try or when
// the webserver is hit by a request to avoid web clients to be
// disconnected while configuring the board
if (jw.getMode() == MODE_ACCESS_POINT) {
if (millis() - wifiLastConnectionTime > WIFI_RECONNECT_INTERVAL) {
wifiConnect();
}
// else reconnect right away
} else {
wifiConnect();
}
}
}

Loading…
Cancel
Save