Initial commit

This commit is contained in:
Dirk Jahnke 2018-01-26 11:22:47 +01:00
parent a178ff5987
commit 649b9e0729
9 changed files with 324 additions and 41 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
build
deps
*.tmp
*.bak

64
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,64 @@
{
"configurations": [
{
"name": "Mac",
"includePath": [
"${workspaceRoot}",
"${workspaceRoot}/src",
"${workspaceRoot}/../modules/mongoose-os/fw/include",
"${workspaceRoot}/../modules/mongoose-os/common",
"${workspaceRoot}/../modules/mjs"
],
"defines": [],
"intelliSenseMode": "clang-x64",
"browse": {
"path": [
"${workspaceRoot}"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
},
"macFrameworkPath": []
},
{
"name": "Linux",
"includePath": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}"
],
"defines": [],
"intelliSenseMode": "clang-x64",
"browse": {
"path": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
}
},
{
"name": "Win32",
"includePath": [
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include",
"${workspaceRoot}"
],
"defines": [
"_DEBUG",
"UNICODE"
],
"intelliSenseMode": "msvc-x64",
"browse": {
"path": [
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include/*",
"${workspaceRoot}"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
}
}
],
"version": 3
}

View File

@ -1,12 +1,19 @@
# Setup WiFi via Web UI
# SonOff module based on Mongoose-OS and using MQTT to integrate to some home automation
# Setup via Web and in AP-mode
## Overview
- Do not configure WiFi - leave the module in AP (Access Point mode).
- Mongoose OS starts a WiFi network called `Mongoose_XXXXXX` with password
`Mongoose`. Switch your workstation to that WiFi network
- Mongoose OS starts a WiFi network called `SONOFF_XXXXXX` with password
- if STA is configured and gets access, the AP is disabled ~120 seconds after boot
`Sonoff`. Switch your workstation to that WiFi network
- Point your browser to http://192.168.4.1
- You'll see a simple form to configure WiFi network & password
- You'll see a simple form to configure WiFi network & password and some sonoff parameters
- Integration into your home automation system based on MQTT, please configure
- MQTT host
- MQTT port
- MQTT topic to send current switch status changes (published)
- MQTT topic to subscribe to receive commands
![Screenshot](shot.png)

View File

@ -15,51 +15,32 @@
min-height: 7em; white-space: pre; padding: 0.5em; overflow: auto;
}
</style>
<script src="zepto.min.js"></script>
<script src="s_zepto.min.js"></script>
</head>
<body>
<nav class="nav" tabindex="-1" onclick="this.focus()">
<div class="container">
<a class="pagename current" href="https://mongoose-os.com">Mongoose OS app</a>
<a class="pagename current" href="https://mongoose-os.com">SONOFF / Mongoose</a>
</div>
</nav>
<div class="container">
<div class="hero">
<h1>WiFi setup via Web UI</h1>
<p>This <a href="https://mongoose-os.com">Mongoose OS</a> app shows
how to start a device in Access Point mode (AP) and configure Station mode
via simple Web UI.</p>
<p>This page communicates with the device via
<a href="https://mongoose-os.com/docs/#/rpc/">Mongoose OS RPC mechanism</a>
using HTTP/RESTful as a transport protocol. A small JavaScript library,
<h1>WiFi setup</h1>
<p>Configure your SONOFF device to communicate with your home automation without having this device
connect to some unknown servers on the internet. We want you to keep you under control of your
home!
</p>
<p>This product is based on the Sonoff devices sold by <a href="https://itead.cc">iTead</a>.
The firmware has been replaced by a software based on <a href="https://mongoose-os.com">Mongoose OS</a>.
This setup is developed by <a href="mailto:dirk.jahnke@mailbox.org">Dirk Jahnke</a> and can be found
in a private gitea repository at <a href="https://gitea.pmpark.de/dirk/mg_sonoff.git">https://gitea.pmpark.de/dirk/mg_sonoff.git</a>.
A small JavaScript library,
<a href="http://zeptojs.com/">zepto</a>, is used as a drop-in replacement
for jQuery, for making AJAX calls to the device.
</p>
<p>Open <code>fs/index.html</code>, or right-click on this page and
choose "view source".</p>
<p>
First, this web page makes a call to the
<code>http://DEVICE_IP/rpc/Config.Get</code> RESTful endpoint, which
triggers <code>Config.Get</code> RPC service and returns a large JSON
object (click <a target="_blank" href="/rpc/Config.Get">here</a> to see) with full device configuration. From that object, we take
WiFi SSID and password, and stick them into the text inputs.
</p>
<p>Second, we install a button click handler, which grabs values from the
text inputs, creates a JSON string with the device configuration subtree
that <code>Config.Set</code> RPC call expects,
and calls a <code>/rpc/Config.Set</code> endpoint.
</p>
<p>Similarly, you can call any other RPC service that device has. Call
<code>RPC.List</code> to get a list of all RPC services available.
</p>
</div>
<div class="row form">
<div class="col c4">
<div class="form-control">
<label for="ssid">WiFi Network:</label>
@ -69,15 +50,53 @@
<label for="pass">WiFi Password:</label>
<input type="text" class="smooth" id="pass" name="pass" placeholder="Type WiFi password...">
</div>
<div class="form-control"><button href="#" class="btn btn-sm btn-c" id="save">Save WiFi settings</button></div>
<div class="form-control"><button href="#" class="btn btn-sm btn-c" id="saveWifi">Save WiFi settings &amp; reboot</button></div>
</div>
<div class="col c8">
<!-- <h3>Result:</h3> -->
<div id="result"></div>
</div>
</div>
<div class="row form">
<div class="col c4">
<div class="form-control">
<label for="mqttHost">MQTT Host:</label>
<input type="text" class="smooth" id="mqttHost" name="mqttHost" placeholder="Host name or IP with port ...">
</div>
<div class="form-control">
<label for="mqttPass">MQTT Password:</label>
<input type="text" class="smooth" id="mqttPass" name="mqttPass" placeholder="Type password ...">
</div>
<div class="form-control">
<label for="mqttClientId">MQTT Client ID:</label>
<input type="text" class="smooth" id="mqttClientId" name="mqttClientId" placeholder="Id of this device as a client at MQTT server ...">
</div>
<div class="form-control">
<label for="pubTopic">Publication Topic:</label>
<input type="text" class="smooth" id="mqttPubTopic" name="mqttPubTopic" placeholder="Topic name to publish status changes ...">
</div>
<div class="form-control">
<label for="subTopic">Subscription Topic:</label>
<input type="text" class="smooth" id="mqttSubTopic" name="mqttSubTopic" placeholder="Topic name to receive commands ...">
</div>
<div class="form-control"><button href="#" class="btn btn-sm btn-c" id="saveSonoff">Save device settings &amp; reboot</button></div>
</div>
<div class="col c4">
<div id="more"></div>
</div>
<div class="col c4">
<h3>Device Info</h3>
<div class="form-control">
<label for="deviceID">Device ID:</label>
<input type="text" class="smooth" id="mqttPubTopic" name="mqttPubTopic" readonly="readonly">
</div>
</div>
</div>
</div>
<script>
@ -92,10 +111,16 @@
log('Result: ' + JSON.stringify(data));
$('#ssid').val(data.wifi.sta.ssid);
$('#pass').val(data.wifi.sta.pass);
$('#deviceID').val(data.device.id);
$('#mqttHost').val(data.mqtt.server);
$('#mqttPass').val(data.mqtt.pass);
$('#mqttClientId').val(data.mqtt.client_id);
$('#pubTopic').val(data.sonoff.switch_status_pub_topic);
$('#subTopic').val(data.sonoff.command_sub_topic);
},
});
$('#save').on('click', function() {
$('#saveWifi').on('click', function() {
log('Calling /rpc/Config.Set ...');
$.ajax({
url: '/rpc/Config.Set',
@ -109,6 +134,19 @@
})
});
$('#saveSonoff').on('click', function() {
log('Calling /rpc/Config.Set ...');
$.ajax({
url: '/rpc/Config.Set',
data: JSON.stringify({config: {mqtt: {enable: true, server: $('#mqttHost').val(), client_id: $('#mqttClientId').val()}, pass: $('#mqttPass').val()},sonoff: {switch_status_pub_topic: $('#pubTopic').val(), command_sub_topic: $('#subTopic').val()}}),
type: 'POST',
// contentType: 'application/json',
success: function(data) {
log('Success. Saving and rebooting ...');
$.ajax({url: '/rpc/Config.Save', type: 'POST', data: JSON.stringify({"reboot": true})});
},
})
});
</script>
</body>

39
mos.yml
View File

@ -1,21 +1,54 @@
author: mongoose-os
description: Setup WiFi via Web UI
name: mg_sonoff
author: Dirk Jahnke
description: Control sonoff devices without having them communicate to their internet servers. Instead integrate them into you own home automation based on MQTT or RPC.
version: 1.0
libs_version: ${mos.version}
modules_version: ${mos.version}
mongoose_os_version: ${mos.version}
platforms: [esp8266]
arch: esp8266
filesystem:
- fs
libs:
- origin: https://github.com/mongoose-os-libs/ca-bundle
- origin: https://github.com/mongoose-os-libs/i2c
- origin: https://github.com/mongoose-os-libs/http-server
- origin: https://github.com/mongoose-os-libs/ota-http-server
- origin: https://github.com/mongoose-os-libs/mqtt
- origin: https://github.com/mongoose-os-libs/rpc-service-config
- origin: https://github.com/mongoose-os-libs/rpc-service-fs
- origin: https://github.com/mongoose-os-libs/rpc-uart
# - origin: https://github.com/mongoose-os-libs/rpc-uart
- origin: https://github.com/mongoose-os-libs/rpc-mqtt
- origin: https://github.com/mongoose-os-libs/wifi
# - origin: https://github.com/mongoose-os-libs/mjs
cdefs:
MGOS_ENABLE_WEB_CONFIG: 1
MGOS_ENABLE_FILE_UPLOAD: 1
MGOS_ENABLE_TUNNEL: 0
config_schema:
- ["http.enable", true]
# - ["http.document_root", "/"]
# - ["http.hidden_files", "s_*"]
# - ["http.auth_file", "s_pass"]
- ["wifi.ap.enable", true]
- ["wifi.ap.ssid", "SONOFF_??????"]
- ["wifi.ap.pass", "MySonoff"]
# - ["wifi.sta.enable", false]
- ["sonoff", "o", {title: "Sonoff specific parameters"}]
- ["sonoff.switch_status_pub_topic", "s", "sonoff/??????/switch", {title: "Topic to publish switch status, ?????? is the device ID of this device"}]
- ["sonoff.command_sub_topic", "s", "sonoff/??????/command", {title: "Topic to subscribe to receive commands for this device"}]
build_vars:
# sonoff basic has 1MBytes flash only
FLASH_SIZE: 1048576
tags:
- c

59
src/ledHandler.c Normal file
View File

@ -0,0 +1,59 @@
// Author: Dirk Jahnke
// January 24, 2018
//
// Manage on board LED of SONOFF device
//
#include <stdio.h>
#include <time.h>
#include "mgos.h"
#include "mgos_gpio.h"
#include "mgos_sys_config.h"
#include "mgos_timers.h"
#include "ledHandler.h"
static int ON_BOARD_LED = 13; /* sonoff basic LED pin */
static LEDStatus currentStatus = LED_OFF;
static int numTicksLedHasThisState = 0;
void set_led_status(LEDStatus newStatus) {
numTicksLedHasThisState = 0;
currentStatus = newStatus;
LOG(LL_DEBUG, ("set_led_status to %d", newStatus));
}
static uint8_t led_timer_ticks = 0; /* for led blinker use */
static void blink_on_board_led_cb(void *arg) {
switch (currentStatus) {
case LED_OFF:
mgos_gpio_write(ON_BOARD_LED, 1); // off
break;
case LED_ON:
mgos_gpio_write(ON_BOARD_LED, 0); // on
break;
case LED_BLINK_SLOW:
++numTicksLedHasThisState = 0;
if (numTicksLedHasThisState >= 4) {
numTicksLedHasThisState = 0;
mgos_gpio_toggle(ON_BOARD_LED);
}
break;
case LED_BLINK_FAST:
// toggle LED each tick
mgos_gpio_toggle(ON_BOARD_LED);
break;
default:
LOG(LL_ERROR, ("Invalid current LED status: %d -- ignored", currentStatus));
break;
}
(void) arg;
}
void init_led_handler() {
mgos_gpio_set_mode(ON_BOARD_LED, MGOS_GPIO_MODE_OUTPUT);
mgos_set_timer(250, MGOS_TIMER_REPEAT, blink_on_board_led_cb, NULL);
LOG(LL_DEBUG, ("LED handler initialized"));
}

19
src/ledHandler.h Normal file
View File

@ -0,0 +1,19 @@
// Author: Dirk Jahnke
// January 24, 2018
//
// Manage on board LED of SONOFF device
//
#ifndef ledHandler_h_included
#define ledHandler_h_included
enum LEDStatus {
LED_OFF = 0, // permanently off
LED_ON = 1, // permanently on
LED_BLINK_SLOW = 2, // on 0,5x / second (1s on, 1s off)
LED_BLINK_FAST = 3 // on 2x / second (250ms on, 250ms off)
};
extern void set_led_status(LEDStatus newStatus);
extern void init_led_handler();
#endif

58
src/main.c Normal file
View File

@ -0,0 +1,58 @@
#include <stdio.h>
#include <time.h>
#include "common/platform.h"
#include "common/cs_file.h"
#include "mgos_app.h"
#include "mgos_gpio.h"
#include "mgos_sys_config.h"
#include "mgos_timers.h"
#include "mgos_hal.h"
#include "mgos_dlsym.h"
#include "mgos_mqtt.h"
#include "mjs.h"
#include "ledHandler.h"
bool mqtt_conn_flag = false;
int mqtt_connected(void) {
return (int) mqtt_conn_flag;
}
//static void pub(struct mg_connection *c, const char *fmt, ...) {
//char msg[200];
//struct json_out jmo = JSON_OUT_BUF(msg, sizeof(msg));
//va_list ap;
//int n;
//va_start(ap, fmt);
//n = json_vprintf(&jmo, fmt, ap);
//va_end(ap);
//mg_mqtt_publish(c, get_cfg()->mqtt.pub, 0, MG_MQTT_QOS(0), msg, n);
//LOG(LL_INFO, ("%s -> %s", get_cfg()->mqtt.pub, msg));
//}
static void mqtt_ev_handler(struct mg_connection *c, int ev, void *p, void *user_data) {
struct mg_mqtt_message *msg = (struct mg_mqtt_message *) p;
if (ev == MG_EV_MQTT_CONNACK) {
LOG(LL_INFO, ("MQTT connected: %d", msg->connack_ret_code));
mqtt_conn_flag = true;
//if (get_cfg()->mqtt.pub == NULL) {
//LOG(LL_ERROR, ("Run 'mos config-set mqtt.pub=... '"));
//} else {
//pub(c, "{timestamp:%.3lf, mem_free:%d}", mg_time(), mgos_get_free_heap_size() ); /* post uptime */
//}
} else if (ev == MG_EV_CLOSE) {
mqtt_conn_flag = false;
}
(void) user_data;
(void) c;
}
enum mgos_app_init_result mgos_app_init(void) {
init_led_handler();
mgos_mqtt_add_global_handler(mqtt_ev_handler, NULL);
LOG(LL_DEBUG, ("SONOFF app initialized"));
return MGOS_APP_INIT_SUCCESS;
}