Browse Source

RFBridge web intrface

fastled
Xose Pérez 7 years ago
parent
commit
cf714106fb
6 changed files with 200 additions and 25 deletions
  1. +1
    -1
      code/espurna/relay.ino
  2. +39
    -19
      code/espurna/rfbridge.ino
  3. +31
    -2
      code/espurna/web.ino
  4. +23
    -3
      code/html/custom.css
  5. +62
    -0
      code/html/custom.js
  6. +44
    -0
      code/html/index.html

+ 1
- 1
code/espurna/relay.ino View File

@ -40,7 +40,7 @@ void relayProviderStatus(unsigned char id, bool status) {
if (id >= _relays.size()) return; if (id >= _relays.size()) return;
#if RELAY_PROVIDER == RELAY_PROVIDER_RFBRIDGE #if RELAY_PROVIDER == RELAY_PROVIDER_RFBRIDGE
rfbState(id, status);
rfbStatus(id, status);
#endif #endif
#if RELAY_PROVIDER == RELAY_PROVIDER_DUAL #if RELAY_PROVIDER == RELAY_PROVIDER_DUAL


+ 39
- 19
code/espurna/rfbridge.ino View File

@ -29,7 +29,7 @@ Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
unsigned char _uartbuf[RF_MESSAGE_SIZE+3] = {0}; unsigned char _uartbuf[RF_MESSAGE_SIZE+3] = {0};
unsigned char _uartpos = 0; unsigned char _uartpos = 0;
unsigned char _learnId = 0; unsigned char _learnId = 0;
bool _learnState = true;
bool _learnStatus = true;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// PRIVATES // PRIVATES
@ -46,6 +46,7 @@ void _rfbAck() {
} }
void _rfbLearn() { void _rfbLearn() {
DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending LEARN\n")); DEBUG_MSG_P(PSTR("[RFBRIDGE] Sending LEARN\n"));
Serial.println(); Serial.println();
Serial.write(RF_CODE_START); Serial.write(RF_CODE_START);
@ -53,6 +54,11 @@ void _rfbLearn() {
Serial.write(RF_CODE_STOP); Serial.write(RF_CODE_STOP);
Serial.flush(); Serial.flush();
Serial.println(); Serial.println();
char wsb[100];
sprintf_P(wsb, PSTR("{\"action\": \"rfbLearn\", \"data\":{\"id\": %d, \"status\": %d}}"), _learnId, _learnStatus ? 1 : 0);
wsSend(wsb);
} }
void _rfbSend(byte * message) { void _rfbSend(byte * message) {
@ -92,6 +98,7 @@ void _rfbDecode() {
if (action == RF_CODE_LEARN_KO) { if (action == RF_CODE_LEARN_KO) {
_rfbAck(); _rfbAck();
DEBUG_MSG_P(PSTR("[RFBRIDGE] Learn timeout\n")); DEBUG_MSG_P(PSTR("[RFBRIDGE] Learn timeout\n"));
wsSend("{\"action\": \"rfbTimeout\"}");
} }
if (action == RF_CODE_LEARN_OK || action == RF_CODE_RFIN) { if (action == RF_CODE_LEARN_OK || action == RF_CODE_RFIN) {
@ -101,9 +108,15 @@ void _rfbDecode() {
} }
if (action == RF_CODE_LEARN_OK) { if (action == RF_CODE_LEARN_OK) {
// TODO: notify websocket
_rfbStore(_learnId, _learnState, buffer);
DEBUG_MSG_P(PSTR("[RFBRIDGE] Learn success. Storing %d-%s => '%s'\n"), _learnId, _learnState ? "ON" : "OFF", buffer);
DEBUG_MSG_P(PSTR("[RFBRIDGE] Learn success\n");
rfbStore(_learnId, _learnStatus, buffer);
// Websocket update
char wsb[100];
sprintf_P(wsb, PSTR("{\"rfb\":[{\"id\": %d, \"status\": %d, \"data\": \"%s\"}]}"), _learnId, _learnStatus ? 1 : 0, buffer);
wsSend(wsb);
} }
if (action == RF_CODE_RFIN) { if (action == RF_CODE_RFIN) {
@ -111,11 +124,11 @@ void _rfbDecode() {
DEBUG_MSG_P(PSTR("[RFBRIDGE] Forward message '%s'\n"), buffer); DEBUG_MSG_P(PSTR("[RFBRIDGE] Forward message '%s'\n"), buffer);
// Look for the code // Look for the code
unsigned char id, state;
unsigned char id, status;
bool found = false; bool found = false;
for (id=0; id<relayCount(); id++) { for (id=0; id<relayCount(); id++) {
for (state=0; state<2; state++) {
String code = _rfbRetrieve(id, state == 1);
for (status=0; status<2; status++) {
String code = rfbRetrieve(id, status == 1);
if (code.length()) { if (code.length()) {
if (code.endsWith(&buffer[12])) { if (code.endsWith(&buffer[12])) {
found = true; found = true;
@ -125,7 +138,7 @@ void _rfbDecode() {
} }
if (found) break; if (found) break;
} }
if (found) relayStatus(id, state == 1);
if (found) relayStatus(id, status == 1);
} }
@ -203,7 +216,7 @@ void _rfbMqttCallback(unsigned int type, const char * topic, const char * payloa
DEBUG_MSG_P(PSTR("[RFBRIDGE] Wrong learnID (%d)\n"), _learnId); DEBUG_MSG_P(PSTR("[RFBRIDGE] Wrong learnID (%d)\n"), _learnId);
return; return;
} }
_learnState = (char)payload[0] != '0';
_learnStatus = (char)payload[0] != '0';
_rfbLearn(); _rfbLearn();
} }
@ -219,25 +232,25 @@ void _rfbMqttCallback(unsigned int type, const char * topic, const char * payloa
} }
void _rfbStore(unsigned char id, bool status, char * code) {
// -----------------------------------------------------------------------------
// PUBLIC
// -----------------------------------------------------------------------------
void rfbStore(unsigned char id, bool status, const char * code) {
DEBUG_MSG_P(PSTR("[RFBRIDGE] Storing %d-%s => '%s'\n"), id, status ? "ON" : "OFF", code);
char key[8] = {0}; char key[8] = {0};
sprintf(key, "rfb%d%s", id, status ? "on" : "off"); sprintf(key, "rfb%d%s", id, status ? "on" : "off");
setSetting(key, code); setSetting(key, code);
} }
String _rfbRetrieve(unsigned char id, bool status) {
String rfbRetrieve(unsigned char id, bool status) {
char key[8] = {0}; char key[8] = {0};
sprintf(key, "rfb%d%s", id, status ? "on" : "off"); sprintf(key, "rfb%d%s", id, status ? "on" : "off");
return getSetting(key); return getSetting(key);
} }
// -----------------------------------------------------------------------------
// PUBLIC
// -----------------------------------------------------------------------------
void rfbState(unsigned char id, bool status) {
String value = _rfbRetrieve(id, status);
DEBUG_MSG_P(PSTR("[RFBRIDGE] Retrieving value for %d-%s => %s\n"), id, status ? "ON" : "OFF", value.c_str());
void rfbStatus(unsigned char id, bool status) {
String value = rfbRetrieve(id, status);
if (value.length() > 0) { if (value.length() > 0) {
byte message[RF_MESSAGE_SIZE]; byte message[RF_MESSAGE_SIZE];
_rfbToArray(value.c_str(), message); _rfbToArray(value.c_str(), message);
@ -247,14 +260,21 @@ void rfbState(unsigned char id, bool status) {
void rfbLearn(unsigned char id, bool status) { void rfbLearn(unsigned char id, bool status) {
_learnId = id; _learnId = id;
_learnState = status;
_learnStatus = status;
_rfbLearn(); _rfbLearn();
} }
void rfbForget(unsigned char id, bool status) { void rfbForget(unsigned char id, bool status) {
char key[8] = {0}; char key[8] = {0};
sprintf(key, "rfb%d%s", id, status ? "on" : "off"); sprintf(key, "rfb%d%s", id, status ? "on" : "off");
delSetting(key); delSetting(key);
// Websocket update
char wsb[100];
sprintf_P(wsb, PSTR("{\"rfb\":[{\"id\": %d, \"status\": %d, \"data\": \"\"}]}"), id, status ? 1 : 0);
wsSend(wsb);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------


+ 31
- 2
code/espurna/web.ino View File

@ -88,6 +88,21 @@ void _wsParse(uint32_t client_id, uint8_t * payload, size_t length) {
ESP.restart(); ESP.restart();
} }
#ifdef SONOFF_RFBRIDGE
if (action.equals("rfblearn") && root.containsKey("data")) {
JsonObject& data = root["data"];
rfbLearn(data["id"], data["status"]);
}
if (action.equals("rfbforget") && root.containsKey("data")) {
JsonObject& data = root["data"];
rfbForget(data["id"], data["status"]);
}
if (action.equals("rfbsend") && root.containsKey("data")) {
JsonObject& data = root["data"];
rfbStore(data["id"], data["status"], data["data"].as<const char*>());
}
#endif
if (action.equals("restore") && root.containsKey("data")) { if (action.equals("restore") && root.containsKey("data")) {
JsonObject& data = root["data"]; JsonObject& data = root["data"];
@ -125,7 +140,7 @@ void _wsParse(uint32_t client_id, uint8_t * payload, size_t length) {
if (data.containsKey("status")) { if (data.containsKey("status")) {
bool state = (strcmp(data["status"], "1") == 0);
bool status = (strcmp(data["status"], "1") == 0);
unsigned int relayID = 0; unsigned int relayID = 0;
if (data.containsKey("id")) { if (data.containsKey("id")) {
@ -133,7 +148,7 @@ void _wsParse(uint32_t client_id, uint8_t * payload, size_t length) {
relayID = value.toInt(); relayID = value.toInt();
} }
relayStatus(relayID, state);
relayStatus(relayID, status);
} }
@ -560,6 +575,20 @@ void _wsStart(uint32_t client_id) {
root["powPowerFactor"] = String(getPowerFactor(), 2); root["powPowerFactor"] = String(getPowerFactor(), 2);
#endif #endif
#ifdef SONOFF_RFBRIDGE
root["rfbVisible"] = 1;
root["rfbCount"] = relayCount();
JsonArray& rfb = root.createNestedArray("rfb");
for (byte id=0; id<relayCount(); id++) {
for (byte status=0; status<2; status++) {
JsonObject& node = rfb.createNestedObject();
node["id"] = id;
node["status"] = status;
node["data"] = rfbRetrieve(id, status == 1);
}
}
#endif
root["maxNetworks"] = WIFI_MAX_NETWORKS; root["maxNetworks"] = WIFI_MAX_NETWORKS;
JsonArray& wifi = root.createNestedArray("wifi"); JsonArray& wifi = root.createNestedArray("wifi");
for (byte i=0; i<WIFI_MAX_NETWORKS; i++) { for (byte i=0; i<WIFI_MAX_NETWORKS; i++) {


+ 23
- 3
code/html/custom.css View File

@ -46,7 +46,8 @@
background: #1f8dd6; background: #1f8dd6;
} }
.button-reset, .button-reset,
.button-reconnect {
.button-reconnect,
.button-rfb-forget {
background: rgb(202, 60, 60); background: rgb(202, 60, 60);
} }
.button-upgrade { .button-upgrade {
@ -58,13 +59,15 @@
background: rgb(0, 202, 0); background: rgb(0, 202, 0);
margin-left: 5px; margin-left: 5px;
} }
.button-add-network {
.button-add-network,
.button-rfb-learn {
background: rgb(28, 184, 65); background: rgb(28, 184, 65);
} }
.button-del-network { .button-del-network {
background: rgb(202, 60, 60); background: rgb(202, 60, 60);
} }
.button-more-network {
.button-more-network,
.button-rfb-send {
background: rgb(223, 117, 20); background: rgb(223, 117, 20);
} }
.button-settings-backup, .button-settings-backup,
@ -149,3 +152,20 @@ div.state {
.right { .right {
text-align: right; text-align: right;
} }
#panel-rfb fieldset {
margin: 10px 2px;
padding: 20px;
}
#panel-rfb input {
margin-right: 5px;
}
#panel-rfb label {
padding-top: 5px;
}
#panel-rfb input {
text-align: center;
}

+ 62
- 0
code/html/custom.js View File

@ -284,6 +284,45 @@ function addNetwork() {
} }
function addRfbNode() {
var numNodes = $("#rfbNodes > fieldset").length;
var template = $("#rfbNodeTemplate").children();
var line = $(template).clone();
var status = true;
$("span", line).html(numNodes+1);
$(line).find("input").each(function() {
$(this).attr("data_id", numNodes);
$(this).attr("data_status", status ? 1 : 0);
status = !status;
});
$(line).find(".button-rfb-learn").on('click', rfbLearn);
$(line).find(".button-rfb-forget").on('click', rfbForget);
$(line).find(".button-rfb-send").on('click', rfbSend);
line.appendTo("#rfbNodes");
return line;
}
function rfbLearn() {
var parent = $(this).parents(".pure-g");
var input = $("input", parent);
websock.send(JSON.stringify({'action': 'rfblearn', 'data' : {'id' : input.attr("data_id"), 'status': input.attr("data_status")}}));
}
function rfbForget() {
var parent = $(this).parents(".pure-g");
var input = $("input", parent);
websock.send(JSON.stringify({'action': 'rfbforget', 'data' : {'id' : input.attr("data_id"), 'status': input.attr("data_status")}}));
}
function rfbSend() {
var parent = $(this).parents(".pure-g");
var input = $("input", parent);
websock.send(JSON.stringify({'action': 'rfbsend', 'data' : {'id' : input.attr("data_id"), 'status': input.attr("data_status"), 'data': input.val()}}));
}
function forgetCredentials() { function forgetCredentials() {
$.ajax({ $.ajax({
'method': 'GET', 'method': 'GET',
@ -337,10 +376,33 @@ function processData(data) {
}, 1000); }, 1000);
} }
if (data.action == "rfbLearn") {
// Nothing to do?
}
if (data.action == "rfbTimeout") {
// Nothing to do?
}
return; return;
} }
if (key == "rfbCount") {
for (var i=0; i<data.rfbCount; i++) addRfbNode();
return;
}
if (key == "rfb") {
var nodes = data.rfb;
for (var i in nodes) {
var node = nodes[i];
var element = $("input[name=rfbcode][data_id=" + node["id"] + "][data_status=" + node["status"] + "]");
if (element.length) element.val(node["data"]);
}
return;
}
if (key == "color") { if (key == "color") {
$("input[name='color']").wheelColorPicker('setValue', data[key], true); $("input[name='color']").wheelColorPicker('setValue', data[key], true);
return; return;


+ 44
- 0
code/html/index.html View File

@ -114,6 +114,10 @@
<a href="#" class="pure-menu-link" data="panel-power">POWER</a> <a href="#" class="pure-menu-link" data="panel-power">POWER</a>
</li> </li>
<li class="pure-menu-item module module-rfb">
<a href="#" class="pure-menu-link" data="panel-rfb">RFBRIDGE</a>
</li>
<li class="pure-menu-item"> <li class="pure-menu-item">
<a href="#" class="pure-menu-link" data="panel-admin">ADMIN</a> <a href="#" class="pure-menu-link" data="panel-admin">ADMIN</a>
</li> </li>
@ -707,12 +711,52 @@
</div> </div>
</form> </form>
<div class="panel" id="panel-rfb">
<div class="header">
<h1>RFBRIDGE</h1>
<h2>Sonoff 433 RF Bridge Configuration</h2>
</div>
<div class="page">
<div id="rfbNodes" />
</div>
</div>
</div> <!-- content --> </div> <!-- content -->
</div> <!-- layout --> </div> <!-- layout -->
<!-- Templates --> <!-- Templates -->
<div id="rfbNodeTemplate" class="template">
<fieldset>
<legend>&nbsp;Switch <span></span>&nbsp;</legend>
<div class="pure-g">
<label class="pure-u-1-2 pure-u-sm-1-4">Switch ON</label>
<input class="pure-u-1-2 pure-u-sm-1-3" type="text" maxlength="18" name="rfbcode" data_id="1" data_status="1" />
<div class="pure-u-1-3 pure-u-md-1-8"><button type="button" class="pure-u-23-24 pure-button button-rfb-learn">LEARN</button></div>
<div class="pure-u-1-3 pure-u-md-1-8"><button type="button" class="pure-u-23-24 pure-button button-rfb-send">SAVE</button></div>
<div class="pure-u-1-3 pure-u-md-1-8"><button type="button" class="pure-u-23-24 pure-button button-rfb-forget">FORGET</button></div>
</div>
<div class="pure-g">
<label class="pure-u-1-2 pure-u-sm-1-4">Switch OFF</label>
<input class="pure-u-1-2 pure-u-sm-1-3" type="text" maxlength="18" name="rfbcode" data_id="1" data_status="0" />
<div class="pure-u-1-3 pure-u-md-1-8"><button type="button" class="pure-u-23-24 pure-button button-rfb-learn">LEARN</button></div>
<div class="pure-u-1-3 pure-u-md-1-8"><button type="button" class="pure-u-23-24 pure-button button-rfb-send">SAVE</button></div>
<div class="pure-u-1-3 pure-u-md-1-8"><button type="button" class="pure-u-23-24 pure-button button-rfb-forget">FORGET</button></div>
</div>
</fieldset>
</div>
<div id="networkTemplate" class="template"> <div id="networkTemplate" class="template">
<div class="pure-g"> <div class="pure-g">


Loading…
Cancel
Save