initial commit
This commit is contained in:
commit
43173dde6e
|
@ -0,0 +1,117 @@
|
|||
const Main = imports.ui.main;
|
||||
const St = imports.gi.St;
|
||||
const GObject = imports.gi.GObject;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
|
||||
const LMAP_HOSTNAME = "lamp.lan"
|
||||
const LMAP_PORT = 2000
|
||||
|
||||
let rlamp;
|
||||
|
||||
const RLamp = GObject.registerClass(
|
||||
class RLamp extends PanelMenu.Button {
|
||||
// From https://github.com/jeffchannell/gnome-shell-socket/blob/master/client.js
|
||||
sendRequest(request)
|
||||
{
|
||||
try
|
||||
{
|
||||
let lampAddress = Gio.NetworkAddress.new(LMAP_HOSTNAME, LMAP_PORT);
|
||||
let client = new Gio.SocketClient();
|
||||
client.set_timeout(1.0);
|
||||
let connection = client.connect(lampAddress, null);
|
||||
if (!connection) {
|
||||
throw "Failed to connect to lamp on: " + lampAddress.get_hostname()
|
||||
}
|
||||
|
||||
let input = connection.get_input_stream();
|
||||
let output = connection.get_output_stream();
|
||||
|
||||
output.write_bytes(new GLib.Bytes(''+request), null);
|
||||
|
||||
let response = String.fromCharCode.apply(null, input.read_bytes(1024, null).get_data());
|
||||
|
||||
connection.close(null);
|
||||
return response
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
getStatus()
|
||||
{
|
||||
for(let i = 0; i < 5; i++)
|
||||
{
|
||||
let response = this.sendRequest("status");
|
||||
if(response.lenght < 1)
|
||||
continue;
|
||||
return (this.sendRequest("status") === "on");
|
||||
}
|
||||
}
|
||||
|
||||
updateWidgets(shouldBeOn)
|
||||
{
|
||||
if (shouldBeOn)
|
||||
{
|
||||
this.lampSwitch.label.text = "Turn Lamp On";
|
||||
this.lampSwitch.setToggleState(true);
|
||||
this.rlampIcon.icon_name = 'weather-clear-day';
|
||||
}
|
||||
else
|
||||
{
|
||||
this.lampSwitch.label.text = "Turn Lamp Off";
|
||||
this.lampSwitch.setToggleState(false);
|
||||
this.rlampIcon.icon_name = 'weather-clear-night';
|
||||
}
|
||||
}
|
||||
|
||||
commandSwitch(shouldBeOn)
|
||||
{
|
||||
this.sendRequest(shouldBeOn ? "on" : "off");
|
||||
this.updateWidgets(shouldBeOn);
|
||||
}
|
||||
|
||||
_init ()
|
||||
{
|
||||
super._init(0);
|
||||
|
||||
// Panel icon
|
||||
this.rlampIcon = new St.Icon({
|
||||
icon_name : 'weather-clear-night',
|
||||
style_class : 'system-status-icon',
|
||||
});
|
||||
this.rlampIcon.connect('button-press-event', (item, state) => {
|
||||
this.updateWidgets(this.getStatus());
|
||||
});
|
||||
this.add_child(this.rlampIcon);
|
||||
|
||||
// Lamp switch
|
||||
this.lampSwitch = new PopupMenu.PopupSwitchMenuItem('Lamp',
|
||||
false, {});
|
||||
this.lampSwitch.connect('toggled', (item, state) => {
|
||||
this.commandSwitch(state);
|
||||
});
|
||||
this.menu.addMenuItem(this.lampSwitch);
|
||||
|
||||
// Get the initial state of the lamp and update the widgets
|
||||
this.updateWidgets(this.getStatus());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function init() {
|
||||
}
|
||||
|
||||
function enable() {
|
||||
rlamp = new RLamp();
|
||||
Main.panel.addToStatusArea('rlamp', rlamp, 1);
|
||||
}
|
||||
|
||||
function disable() {
|
||||
rlamp.destroy();
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "rlamp",
|
||||
"description": "Lamp control switch for Wifi activated lamp",
|
||||
"uuid": "rlamp@jmq.sh",
|
||||
"shell-version": [
|
||||
"43"
|
||||
],
|
||||
"settings-schema": "org.gnome.shell.extensions.rlamp"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
*.compiled
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<schemalist>
|
||||
<schema id="org.gnome.shell.extensions.rlamp" path="/org/gnome/shell/extensions/rlamp/">
|
||||
<key name="hostname" type="s">
|
||||
<default>"lamp.lan"</default>
|
||||
</key>
|
||||
<key name="port" type="i">
|
||||
<default>2000</default>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
|
@ -0,0 +1 @@
|
|||
/* Add your custom extension styling here */
|
|
@ -0,0 +1,571 @@
|
|||
#include <string.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "LittleFS.h"
|
||||
|
||||
#include <WiFiClient.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
#include <ESP8266WiFiMulti.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
|
||||
#define SERIAL_BAUDRATE 115200
|
||||
|
||||
#define WIFI_SSID_PATH "/ssid"
|
||||
#define WIFI_PASS_PATH "/pass"
|
||||
#define ALLOWED_CLIENTS_PATH "/allowed"
|
||||
#define IP_PATH "/ip"
|
||||
#define GATEWAY_PATH "/gateway"
|
||||
#define SUBNET_MASK_PATH "/subnet"
|
||||
#define PORT_PATH "/port"
|
||||
|
||||
#define HOST_SEPARATOR_TAB ','
|
||||
#define WIFI_MAX_CONCECTION_TRIES 50
|
||||
#define WIFI_MIN_PORT 1000
|
||||
|
||||
#define RELAY_DEFAULT_DATA_PIN D7
|
||||
|
||||
#define MAX_PRINTF_BUFFER 128
|
||||
#define MAX_TCP_BUFFER_SIZE 10
|
||||
#define MAX_CMD_BUFFER_SIZE 256
|
||||
#define FILE_BUF_SIZE 128
|
||||
#define COMMAND_PROMPT "~ "
|
||||
|
||||
#define arrlen(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
#define CREATE_SETTING_ACCESSOR(_name, _path) \
|
||||
int \
|
||||
set##_name(const String &val) \
|
||||
{ \
|
||||
int ret = 0; \
|
||||
ret = writeToFile(#_path, val); \
|
||||
if(ret) \
|
||||
{ \
|
||||
LOG("cannot set "#_name": (%d)", ret); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
LOG(#_name " has been set to \"%s\"", \
|
||||
val.c_str()) \
|
||||
} \
|
||||
\
|
||||
return ret; \
|
||||
} \
|
||||
String \
|
||||
get##_name() \
|
||||
{ \
|
||||
String val = ""; \
|
||||
int ret = 0; \
|
||||
ret = readFromFile(#_path, val); \
|
||||
if(ret) \
|
||||
{ \
|
||||
LOG("cannot get value for "#_name":" \
|
||||
"(%d)", ret); \
|
||||
return ""; \
|
||||
} \
|
||||
return val; \
|
||||
}
|
||||
|
||||
#define _printf(_fmt, ...) \
|
||||
{ \
|
||||
sprintf(_PRINTF_BUF,_fmt"%s", __VA_ARGS__, \
|
||||
"\0"); \
|
||||
Serial.print(_PRINTF_BUF); \
|
||||
}
|
||||
#define printf(...) _printf(__VA_ARGS__,"")
|
||||
#define _LOG(_fmt, ...) _printf(_fmt "\n", __VA_ARGS__)
|
||||
#define LOG(...) _LOG(__VA_ARGS__,"")
|
||||
|
||||
struct
|
||||
{
|
||||
int port;
|
||||
|
||||
String ssid, pass;
|
||||
std::vector<IPAddress> allowedHosts;
|
||||
|
||||
IPAddress ip, gateway, submask;
|
||||
} settings;
|
||||
|
||||
struct command_t
|
||||
{
|
||||
const char * name, * description;
|
||||
int (*func)(const String &argument);
|
||||
};
|
||||
|
||||
static char CMD_BUFFER[MAX_CMD_BUFFER_SIZE] = {0};
|
||||
static char _PRINTF_BUF[MAX_PRINTF_BUFFER] = {0};
|
||||
|
||||
static WiFiServer wifiServer = WiFiServer(WIFI_MIN_PORT);
|
||||
|
||||
static bool relayState = false;
|
||||
|
||||
void
|
||||
relayOn()
|
||||
{
|
||||
relayState = true;
|
||||
digitalWrite(RELAY_DEFAULT_DATA_PIN, HIGH);
|
||||
}
|
||||
|
||||
void
|
||||
relayOff()
|
||||
{
|
||||
relayState = false;
|
||||
digitalWrite(RELAY_DEFAULT_DATA_PIN, LOW);
|
||||
}
|
||||
|
||||
int
|
||||
writeToFile(const String &path, const String &data)
|
||||
{
|
||||
File file;
|
||||
|
||||
file = LittleFS.open(path, "w");
|
||||
if(!file)
|
||||
{
|
||||
LOG("cannot open \"%s\" file", path.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
file.print(data);
|
||||
file.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
readFromFile(const String &path, String &data)
|
||||
{
|
||||
int i = 0;
|
||||
File file;
|
||||
|
||||
file = LittleFS.open(path, "r");
|
||||
if(!file)
|
||||
{
|
||||
LOG("cannot open \"%s\" file", path.c_str());
|
||||
data = "";
|
||||
return -1;
|
||||
}
|
||||
|
||||
data = file.readString();
|
||||
|
||||
file.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
CREATE_SETTING_ACCESSOR(SSID, WIFI_SSID_PATH)
|
||||
CREATE_SETTING_ACCESSOR(PASS, WIFI_PASS_PATH)
|
||||
CREATE_SETTING_ACCESSOR(AllowedHosts, ALLOWED_CLIENTS_PATH)
|
||||
CREATE_SETTING_ACCESSOR(IP, IP_PATH);
|
||||
CREATE_SETTING_ACCESSOR(Port, PORT_PATH)
|
||||
CREATE_SETTING_ACCESSOR(Gateway, GATEWAY_PATH)
|
||||
CREATE_SETTING_ACCESSOR(SubnetMask, SUBNET_MASK_PATH)
|
||||
|
||||
void
|
||||
updateSettings( void )
|
||||
{
|
||||
IPAddress ip = {0};
|
||||
String allowed = "", current = "";
|
||||
int ret = 0, i = 0, s = 0;
|
||||
bool f = false;
|
||||
|
||||
memset(&settings, 0, sizeof(settings));
|
||||
|
||||
settings.ssid = getSSID();
|
||||
settings.pass = getPASS();
|
||||
|
||||
LOG("WiFi's SSID set to \"%s\"", settings.ssid.c_str());
|
||||
|
||||
ip.fromString(getIP());
|
||||
settings.ip = ip;
|
||||
|
||||
ip.fromString(getGateway());
|
||||
settings.gateway = ip;
|
||||
|
||||
ip.fromString(getSubnetMask());
|
||||
settings.submask = ip;
|
||||
|
||||
settings.allowedHosts.clear();
|
||||
allowed = getAllowedHosts();
|
||||
for(; i < allowed.length(); i++)
|
||||
{
|
||||
if(allowed.charAt(i) == HOST_SEPARATOR_TAB ||
|
||||
(f = (i >= allowed.length() -1)))
|
||||
{
|
||||
if(f)
|
||||
current = allowed.substring(s);
|
||||
else
|
||||
current = allowed.substring(s, i);
|
||||
|
||||
if(ip.fromString(current))
|
||||
{
|
||||
settings.allowedHosts.push_back(ip);
|
||||
LOG("added \"%s\" to allowed hosts", ip.toString());
|
||||
}
|
||||
else
|
||||
{ LOG("invalid host \"%s\"", current.c_str()); }
|
||||
|
||||
s = i+1;
|
||||
}
|
||||
}
|
||||
|
||||
current = getPort();
|
||||
if((i = current.toInt()) >= WIFI_MIN_PORT)
|
||||
{
|
||||
settings.port = i;
|
||||
LOG("server port set to %d", settings.port );
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("invalid port %d", settings.port);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
disconnectFromWifi( void )
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
WiFi.disconnect();
|
||||
ret = -1 ? WiFi.status() == WL_CONNECTED : 0;
|
||||
|
||||
if(!ret)
|
||||
LOG("disconnected from \"%s\"", settings.ssid.c_str());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
String
|
||||
getLocalIP()
|
||||
{
|
||||
return WiFi.localIP().toString();
|
||||
}
|
||||
|
||||
int
|
||||
connectToWifi( void )
|
||||
{
|
||||
int ret = 0, i = 0;
|
||||
|
||||
disconnectFromWifi();
|
||||
|
||||
if(!WiFi.config(settings.ip, settings.gateway, settings.submask))
|
||||
{
|
||||
LOG("failed to apply IPv4 settings");
|
||||
}
|
||||
|
||||
printf("attempting to connect to \"%s\"", settings.ssid.c_str());
|
||||
WiFi.begin(settings.ssid, settings.pass);
|
||||
|
||||
for(; i < WIFI_MAX_CONCECTION_TRIES; i++)
|
||||
{
|
||||
printf(".");
|
||||
|
||||
if(WiFi.status() == WL_CONNECTED)
|
||||
break;
|
||||
|
||||
delay(500);
|
||||
}
|
||||
|
||||
if(WiFi.status() == WL_CONNECTED)
|
||||
{
|
||||
printf("OK!\n");
|
||||
|
||||
wifiServer.stop();
|
||||
wifiServer = WiFiServer(settings.port);
|
||||
wifiServer.begin();
|
||||
|
||||
LOG("connected using IP \"%s\"", getLocalIP());
|
||||
|
||||
LOG("server now listening on port %d", settings.port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("BAD!\n");
|
||||
LOG("failed to connect to \"%s\"", settings.ssid.c_str());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
printAllowedHosts( void )
|
||||
{
|
||||
LOG("%s", getAllowedHosts().c_str());
|
||||
}
|
||||
|
||||
void
|
||||
printInfo( void )
|
||||
{
|
||||
String temp = "";
|
||||
|
||||
LOG("SSID: %s", getSSID());
|
||||
|
||||
temp = (WiFi.status() == WL_CONNECTED) ?
|
||||
"True" : "False";
|
||||
LOG("WiFi connected: %s", temp.c_str());
|
||||
|
||||
LOG("IP: %s", getLocalIP().c_str());
|
||||
|
||||
LOG("Gateway: %s", getGateway().c_str());
|
||||
LOG("SubnetMask: %s", getSubnetMask().c_str());
|
||||
|
||||
printf("Allowed Hosts: ");
|
||||
printAllowedHosts();
|
||||
|
||||
LOG("Port: %s", getPort());
|
||||
}
|
||||
|
||||
void
|
||||
stop( void )
|
||||
{
|
||||
while(1)
|
||||
delay(100);
|
||||
}
|
||||
|
||||
|
||||
const command_t COMMANDS[] PROGMEM = {
|
||||
(command_t){
|
||||
.name = "setSSID",
|
||||
.description = "Set's the SSID the WiFi module"
|
||||
" will connect to",
|
||||
.func = setSSID
|
||||
},
|
||||
(command_t){
|
||||
.name = "setPASS",
|
||||
.description = "Set's the password the WiFi"
|
||||
" module will use to connect to the Access Point",
|
||||
.func = setSSID
|
||||
},
|
||||
(command_t){
|
||||
.name = "connectToWifi",
|
||||
.description = "Connects to the WiFi network",
|
||||
}
|
||||
};
|
||||
|
||||
int
|
||||
processCommand( const String &line )
|
||||
{
|
||||
int i = 0;
|
||||
String command = "", argument = "", temp = "";
|
||||
|
||||
if(line.length() < 1)
|
||||
return -1;
|
||||
|
||||
command = line;
|
||||
|
||||
i = line.indexOf(' ');
|
||||
if(i < line.length() - 1 && i > 0)
|
||||
{
|
||||
command = command.substring(0, i);
|
||||
argument = line.substring(i+1);
|
||||
}
|
||||
|
||||
#define IS_COMMAND(_str) (command.indexOf(_str) == 0)
|
||||
|
||||
if(IS_COMMAND("setSSID"))
|
||||
setSSID(argument);
|
||||
|
||||
else if(IS_COMMAND("setPASS"))
|
||||
setPASS(argument);
|
||||
|
||||
else if(IS_COMMAND("connectToWifi"))
|
||||
connectToWifi();
|
||||
|
||||
else if(IS_COMMAND("clearHosts"))
|
||||
{
|
||||
setAllowedHosts("");
|
||||
}
|
||||
|
||||
else if(IS_COMMAND("addHost"))
|
||||
{
|
||||
temp = getAllowedHosts();
|
||||
if(temp.length() > 0)
|
||||
temp += HOST_SEPARATOR_TAB;
|
||||
|
||||
temp += argument;
|
||||
setAllowedHosts(temp);
|
||||
}
|
||||
|
||||
else if(IS_COMMAND("listHosts"))
|
||||
{
|
||||
printAllowedHosts();
|
||||
}
|
||||
|
||||
else if(IS_COMMAND("info"))
|
||||
{
|
||||
printInfo();
|
||||
}
|
||||
|
||||
else if(IS_COMMAND("setIP"))
|
||||
{
|
||||
setIP(argument);
|
||||
}
|
||||
|
||||
else if(IS_COMMAND("setGateway"))
|
||||
{
|
||||
setGateway(argument);
|
||||
}
|
||||
|
||||
else if(IS_COMMAND("setSubnetMask"))
|
||||
{
|
||||
setSubnetMask(argument);
|
||||
}
|
||||
|
||||
else if(IS_COMMAND("setPort"))
|
||||
{
|
||||
setPort(argument);
|
||||
}
|
||||
|
||||
else if(IS_COMMAND("updateSettings"))
|
||||
{
|
||||
updateSettings();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
LOG("bad command \"%s\"", command.c_str());
|
||||
}
|
||||
|
||||
#undef IS_COMMAND
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
setup( void )
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
pinMode(RELAY_DEFAULT_DATA_PIN, OUTPUT);
|
||||
relayOn();
|
||||
|
||||
Serial.begin(SERIAL_BAUDRATE);
|
||||
printf("\n");
|
||||
if(!LittleFS.begin())
|
||||
{
|
||||
LOG("formatting filesystem....");
|
||||
if(LittleFS.format())
|
||||
LOG("done formatting filesystem");
|
||||
|
||||
if(!LittleFS.begin())
|
||||
LOG("cannot initialize LittleFS");
|
||||
}
|
||||
|
||||
LOG("applying settings...");
|
||||
updateSettings();
|
||||
|
||||
connectToWifi();
|
||||
|
||||
printf(COMMAND_PROMPT);
|
||||
}
|
||||
|
||||
void
|
||||
loop( void )
|
||||
{
|
||||
char tcpBuffer[MAX_TCP_BUFFER_SIZE] = {0};
|
||||
String str;
|
||||
WiFiClient client;
|
||||
int i = 0, s = 0, ret = 0;
|
||||
char c = 0;
|
||||
|
||||
// Handle serial commands
|
||||
if((ret = Serial.available()) > 0 )
|
||||
{
|
||||
static int index = 0;
|
||||
bool valid_character = false;
|
||||
|
||||
c = Serial.read();
|
||||
|
||||
#define CLEAR_BUFFER() \
|
||||
{ \
|
||||
memset(CMD_BUFFER, 0, index*sizeof(CMD_BUFFER[0])); \
|
||||
index = 0; \
|
||||
printf(COMMAND_PROMPT); \
|
||||
}
|
||||
|
||||
if(index > 0 && (c == 13 || c == '\r' || c == '\n'))
|
||||
{
|
||||
printf("\n");
|
||||
processCommand(String(CMD_BUFFER));
|
||||
CLEAR_BUFFER();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(c != '\n' && c != 13)
|
||||
{
|
||||
valid_character = true;
|
||||
switch(c)
|
||||
{
|
||||
case 3:
|
||||
printf("^C\n");
|
||||
CLEAR_BUFFER();
|
||||
valid_character = false;
|
||||
break;
|
||||
case 8:
|
||||
printf("^B");
|
||||
valid_character = false;
|
||||
break;
|
||||
default:
|
||||
printf("%c", c);
|
||||
}
|
||||
}
|
||||
|
||||
if(index < MAX_CMD_BUFFER_SIZE-1 && valid_character)
|
||||
CMD_BUFFER[index++] = c;
|
||||
|
||||
}
|
||||
|
||||
#undef CLEAR_BUFFER
|
||||
|
||||
}
|
||||
|
||||
// Handle IP commands
|
||||
client = wifiServer.available();
|
||||
|
||||
if(client)
|
||||
{
|
||||
i = 1;
|
||||
// i = 0;
|
||||
// for(const IPAddress &c : settings.allowedHosts)
|
||||
// {
|
||||
// if(client.remoteIP() == c)
|
||||
// {
|
||||
// i = 1;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
if(i)
|
||||
{
|
||||
memset(tcpBuffer, 0, arrlen(tcpBuffer));
|
||||
LOG("received valid connection from \"%s\"",
|
||||
client.remoteIP().toString().c_str());
|
||||
|
||||
for(i = 0; i < arrlen(tcpBuffer)-1 && client.available(); i++)
|
||||
tcpBuffer[i] = client.read();
|
||||
|
||||
str = String(tcpBuffer);
|
||||
str.toLowerCase();
|
||||
LOG("command from %s: \"%s\"", client.remoteIP().toString().c_str(), str.c_str());
|
||||
if(str == "on")
|
||||
{
|
||||
LOG("turning relay on");
|
||||
relayOn();
|
||||
}
|
||||
else if(str == "off")
|
||||
{
|
||||
LOG("turning relay off");
|
||||
relayOff();
|
||||
}
|
||||
else if(str == "status")
|
||||
{
|
||||
client.write(relayState ? "on\0" : "off\0");
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
LOG("received invalid request from \"%s\"",
|
||||
client.remoteIP().toString().c_str());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue