diff --git a/devicetypes/konnected-io/konnected-temperature-humidity-sensor-dht.src/konnected-temperature-humidity-sensor-dht.groovy b/devicetypes/konnected-io/konnected-temperature-humidity-sensor-dht.src/konnected-temperature-humidity-sensor-dht.groovy index 2119333..421480e 100644 --- a/devicetypes/konnected-io/konnected-temperature-humidity-sensor-dht.src/konnected-temperature-humidity-sensor-dht.groovy +++ b/devicetypes/konnected-io/konnected-temperature-humidity-sensor-dht.src/konnected-temperature-humidity-sensor-dht.groovy @@ -13,6 +13,7 @@ * for the specific language governing permissions and limitations under the License. * */ + metadata { definition (name: "Konnected Temperature & Humidity Sensor (DHT)", namespace: "konnected-io", author: "konnected.io") { capability "Temperature Measurement" @@ -21,7 +22,7 @@ metadata { preferences { input name: "pollInterval", type: "number", title: "Polling Interval (minutes)", - defaultValue: 3, + defaultValue: defaultPollInterval(), description: "Frequency of sensor updates" } @@ -78,5 +79,9 @@ def updateStates(states) { } def pollInterval() { - return pollInterval + return pollInterval.isNumber() ? pollInterval : defaultPollInterval() +} + +def defaultPollInterval() { + return 3 // minutes } \ No newline at end of file diff --git a/firmware/2.2.0/app/include/user_config.h b/firmware/2.2.0/app/include/user_config.h index 5e4ef3f..c0ad9ba 100644 --- a/firmware/2.2.0/app/include/user_config.h +++ b/firmware/2.2.0/app/include/user_config.h @@ -52,7 +52,9 @@ extern void luaL_assertfail(const char *file, int line, const char *message); #define ICACHE_STORE_TYPEDEF_ATTR __attribute__((aligned(4),packed)) #define ICACHE_STORE_ATTR __attribute__((aligned(4))) -#define ICACHE_RAM_ATTR __attribute__((section(".iram0.text"))) +#define ICACHE_RAM_STRING(x) ICACHE_RAM_STRING2(x) +#define ICACHE_RAM_STRING2(x) #x +#define ICACHE_RAM_ATTR __attribute__((section(".iram0.text." __FILE__ "." ICACHE_RAM_STRING(__LINE__)))) #ifdef GPIO_SAFE_NO_INTR_ENABLE #define NO_INTR_CODE ICACHE_RAM_ATTR __attribute__ ((noinline)) #else @@ -61,7 +63,7 @@ extern void luaL_assertfail(const char *file, int line, const char *message); // SSL buffer size used only for espconn-layer secure connections. // See https://github.com/nodemcu/nodemcu-firmware/issues/1457 for conversation details. -#define SSL_BUFFER_SIZE 6178 +#define SSL_BUFFER_SIZE 4196 #define CLIENT_SSL_ENABLE //#define MD2_ENABLE @@ -78,7 +80,7 @@ extern void luaL_assertfail(const char *file, int line, const char *message); // maximum number of open files for SPIFFS #define SPIFFS_MAX_OPEN_FILES 4 -// Uncomment this next line for fastest startup +// Uncomment this next line for fastest startup // It reduces the format time dramatically // #define SPIFFS_MAX_FILESYSTEM_SIZE 32768 // @@ -114,10 +116,10 @@ extern void luaL_assertfail(const char *file, int line, const char *message); #define WIFI_SDK_EVENT_MONITOR_ENABLE #define WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE -////#define ENABLE_TIMER_SUSPEND -//#define PMSLEEP_ENABLE +//#define PMSLEEP_ENABLE // Enable wifi.suspend() and node.sleep() (NOTE: node.sleep() is dependent on TIMER_SUSPEND_ENABLE) +//#define TIMER_SUSPEND_ENABLE //Required by node.sleep() #define STRBUF_DEFAULT_INCREMENT 32 -#endif /* __USER_CONFIG_H__ */ +#endif /* __USER_CONFIG_H__ */ \ No newline at end of file diff --git a/firmware/2.2.0/app/include/user_modules.h b/firmware/2.2.0/app/include/user_modules.h index d580270..8ca62e2 100644 --- a/firmware/2.2.0/app/include/user_modules.h +++ b/firmware/2.2.0/app/include/user_modules.h @@ -86,5 +86,9 @@ //#define LUA_USE_MODULES_WS2812_EFFECTS //#define LUA_USE_MODULES_XPT2046 +//debug modules +//#define LUA_USE_MODULES_SWTMR_DBG //SWTMR timer suspend Debug functions + + #endif /* LUA_CROSS_COMPILER */ #endif /* __USER_MODULES_H__ */ diff --git a/firmware/konnected-filesystem-0xa0000-32mb.bin b/firmware/konnected-filesystem-0xa0000-32mb.bin index ea085c2..502dce7 100644 Binary files a/firmware/konnected-filesystem-0xa0000-32mb.bin and b/firmware/konnected-filesystem-0xa0000-32mb.bin differ diff --git a/firmware/konnected-firmware-2-2-0.bin b/firmware/konnected-firmware-2-2-1.bin similarity index 63% rename from firmware/konnected-firmware-2-2-0.bin rename to firmware/konnected-firmware-2-2-1.bin index 8b4c4c1..31d8d14 100644 Binary files a/firmware/konnected-firmware-2-2-0.bin and b/firmware/konnected-firmware-2-2-1.bin differ diff --git a/scripts/build-firmware b/scripts/build-firmware index 1b93ced..2289236 100755 --- a/scripts/build-firmware +++ b/scripts/build-firmware @@ -1,7 +1,7 @@ #!/bin/bash FIRMWARE_PATH=${PWD}/../nodemcu-firmware -IMAGE_NAME=konnected-firmware-2-2-0 +IMAGE_NAME=konnected-firmware-2-2-1 cp firmware/2.2.0/app/include/* $FIRMWARE_PATH/app/include/ cp src/* $FIRMWARE_PATH/local/fs diff --git a/scripts/flash b/scripts/flash index b061c9e..9777796 100755 --- a/scripts/flash +++ b/scripts/flash @@ -1,6 +1,6 @@ #!/bin/bash -FIRMWARE_NAME=konnected-firmware-2-2-0 +FIRMWARE_NAME=konnected-firmware-2-2-1 FILESYSTEM_NAME=konnected-filesystem-0xa0000-32mb PORT=/dev/cu.wchusbserial1410 diff --git a/smartapps/konnected-io/konnected-connect.src/konnected-connect.groovy b/smartapps/konnected-io/konnected-connect.src/konnected-connect.groovy index f6ecb0a..3373acb 100644 --- a/smartapps/konnected-io/konnected-connect.src/konnected-connect.groovy +++ b/smartapps/konnected-io/konnected-connect.src/konnected-connect.groovy @@ -13,6 +13,8 @@ * for the specific language governing permissions and limitations under the License. * */ +public static String version() { return "2.2.1" } + definition( name: "Konnected (Connect)", namespace: "konnected-io", @@ -29,6 +31,7 @@ preferences { page(name: "mainPage", title: "Konnected Devices", install: true, uninstall: true) { section { app(name: "childApps", appName: "Konnected Service Manager", namespace: "konnected-io", title: "Add a Konnected device", multiple: true) + paragraph "Konnected (Connect) v${version()}" } } } diff --git a/smartapps/konnected-io/konnected-service-manager.src/konnected-service-manager.groovy b/smartapps/konnected-io/konnected-service-manager.src/konnected-service-manager.groovy index ec1602b..a91275a 100644 --- a/smartapps/konnected-io/konnected-service-manager.src/konnected-service-manager.groovy +++ b/smartapps/konnected-io/konnected-service-manager.src/konnected-service-manager.groovy @@ -13,6 +13,8 @@ * for the specific language governing permissions and limitations under the License. * */ +public static String version() { return "2.2.1" } + definition( name: "Konnected Service Manager", parent: "konnected-io:Konnected (Connect)", @@ -102,6 +104,7 @@ def pageWelcome() { name: "device_" + device.mac, image: "https://docs.konnected.io/assets/favicons/apple-touch-icon.png", title: "Device status", + description: getDeviceIpAndPort(device), url: "http://" + getDeviceIpAndPort(device) ) } else { @@ -116,12 +119,13 @@ def pageWelcome() { section("Help & Support") { href( name: "pageWelcomeManual", - title: "Instructions & Documentation", - description: "Tap to view the online documentation at http://docs.konnected.io", + title: "Instructions & Knowledge Base", + description: "Tap to view the support portal at help.konnected.io", required: false, image: "https://raw.githubusercontent.com/konnected-io/docs/master/assets/images/manual-icon.png", - url: "http://docs.konnected.io/security-alarm-system/" + url: "https://help.konnected.io" ) + paragraph "Konnected Service Manager v${version()}" } } } @@ -170,7 +174,7 @@ private pageSelectHwType() { description: "Tap to select", page: "pageConfiguration", params: [hwType: "alarmPanel"], - image: "https://s3.us-east-2.amazonaws.com/konnected-io/icon-alarmpanel.jpg", + image: "https://s3.us-east-2.amazonaws.com/konnected-io/konnected-alarm-panel-st-icon-t.jpg", ) href( name: "NodeMCU Base", @@ -224,6 +228,22 @@ private pageAssignPins() { } } } + section(title: "Advanced settings") { + input( + name: "blink", + type: "bool", + title: "Blink LED on transmission", + required: false, + defaultValue: true + ) + input( + name: "enableDiscovery", + type: "bool", + title: "Enable device discovery", + required: false, + defaultValue: true + ) + } } } @@ -379,7 +399,7 @@ def updateSettingsOnDevice() { def mac = device.mac getAllChildDevices().each { - def pin = it.deviceNetworkId.split("\\|")[1] + def pin = Integer.parseInt(it.deviceNetworkId.split("\\|")[1]) if (it.name.contains("DHT")) { dht_sensors = dht_sensors + [ pin : pin, poll_interval : it.pollInterval() ] } else if (sensorsMap()[it.name]) { @@ -391,10 +411,14 @@ def updateSettingsOnDevice() { log.debug "Configured sensors on $mac: $sensors" log.debug "Configured actuators on $mac: $actuators" + log.debug "Configured DHT sensors on $mac: $dht_sensors" + log.debug "Blink is: ${settings.blink}" def body = [ token : state.accessToken, apiUrl : apiServerUrl + "/api/smartapps/installations/" + app.id, + blink: settings.blink, + discovery: settings.enableDiscovery, sensors : sensors, actuators : actuators, dht_sensors : dht_sensors diff --git a/spec/device_spec.lua b/spec/device_spec.lua index 887af47..a9cb5e8 100644 --- a/spec/device_spec.lua +++ b/spec/device_spec.lua @@ -7,8 +7,8 @@ describe("device", function() end) it("has expected properties", function() - assert.equal(device.swVersion, "2.1.4") - assert.equal(device.hwVersion, "2.0.5") + assert.equal(device.swVersion, "2.2.1") + assert.equal(device.hwVersion, "2.2.1") assert.equal(device.name, "Konnected") end) diff --git a/spec/nodemcu_stubs.lua b/spec/nodemcu_stubs.lua index ff6605a..77d47fa 100644 --- a/spec/nodemcu_stubs.lua +++ b/spec/nodemcu_stubs.lua @@ -99,6 +99,12 @@ _G.net = { listen = function() end, on = function() end } + end, + createUDPSocket = function() + return { + listen = function() end, + on = function() end + } end } diff --git a/spec/server_device_spec.lua b/spec/server_device_spec.lua index 04b7041..fa8e0cd 100644 --- a/spec/server_device_spec.lua +++ b/spec/server_device_spec.lua @@ -2,28 +2,26 @@ describe("server_device", function() local server, response setup(function() - _G.sjson = require("sjson") + _G.sjson = require("cjson") _G.blinktimer = mock({ start = function() end }) - server = require("server_device") require("spec/nodemcu_stubs") end) describe("updating a device pin state", function() before_each(function() spy.on(_G.gpio, 'write') - response = mock({ send = function(str) end }) end) describe("a normal switch", function() before_each(function() - server.process({ + response = require("server_device")({ contentType = "application/json", method = "PUT", body = { pin = 1, state = 1 } - }, response) + }) end) it("updates the state of the pin", function() @@ -31,14 +29,14 @@ describe("server_device", function() end) it("responds with the new pin state", function() - assert.stub(response.send).was.called_with(sjson.encode({ pin = 1, state = 1 })) + assert.are.equal(response, sjson.encode({ pin = 1, state = 1 })) end) end) describe("a momentary switch", function() before_each(function() - server.process({ + response = require("server_device")({ contentType = "application/json", method = "PUT", body = { @@ -46,7 +44,7 @@ describe("server_device", function() state = 1, momentary = 500 } - }, response) + }) end) it("updates the state of the pin on and then off", function() @@ -58,7 +56,7 @@ describe("server_device", function() end) it("responds with the new pin state", function() - assert.stub(response.send).was.called_with(sjson.encode({ pin = 1, state = 0 })) + assert.are.equal(response, sjson.encode({ pin = 1, state = 0 })) end) end) end) diff --git a/spec/server_spec.lua b/spec/server_spec.lua index a14fb88..3fd6325 100644 --- a/spec/server_spec.lua +++ b/spec/server_spec.lua @@ -6,12 +6,12 @@ describe("server", function() MAN: "ssdp:discover" HOST:239.255.255.250:1900 ST: urn:schemas-konnected-io:device:Security:1 - ]]) + ]], 17234, '192.168.1.111') end setup(function() require("spec/nodemcu_stubs") - _G.net.createServer = function() + _G.net.createUDPSocket = function() return { listen = function() end, on = function(_, event, fn) @@ -24,7 +24,7 @@ describe("server", function() end) before_each(function() - conn = mock({send = function(_, resp) response = resp end}) + conn = mock({send = function(_, port, ip, resp) response = resp end}) nodemcu.wifi.sta.ip = '192.168.1.100' require("server") end) diff --git a/spec/ssdp_spec.lua b/spec/ssdp_spec.lua index 594d99d..2a91926 100644 --- a/spec/ssdp_spec.lua +++ b/spec/ssdp_spec.lua @@ -5,7 +5,7 @@ describe("ssdp", function() before_each(function() require("spec/nodemcu_stubs") nodemcu.wifi.sta.ip = '192.168.1.100' - upnp_response = dofile("src/ssdp.lua") + upnp_response = require("ssdp")() end) it("contains the IP address and port", function() @@ -15,7 +15,7 @@ describe("ssdp", function() it("contains the updated IP address after it changes", function() assert.is.truthy(upnp_response:find("http://" .. nodemcu.wifi.sta.ip .. ":8000")) nodemcu.wifi.sta.ip = '192.168.1.200' - upnp_response = dofile("src/ssdp.lua") + upnp_response = require("ssdp")() assert.is.truthy(upnp_response:find("http://" .. nodemcu.wifi.sta.ip .. ":8000")) end) end) diff --git a/spec/variables_build_spec.lua b/spec/variables_build_spec.lua index 3ffdb8a..0ff64e5 100644 --- a/spec/variables_build_spec.lua +++ b/spec/variables_build_spec.lua @@ -5,20 +5,35 @@ describe("variables_build", function() return s:gsub('%c','') end - setup(function() - variables_build = require('variables_build') + it("returns a string that makes a lua list of lists", function() + local thing = {{pin=1},{pin=2}} + local str = require('variables_build')(thing) + assert.same(thing, load("return " .. str)()) end) - it("returns a string that makes a lua list", function() - local str = variables_build.build({{pin=1},{pin=2}}) - assert.same("{ { pin = 1, },{ pin = 2, },}", trim(str) ) + it("returns a sting that makes a lua list", function() + local thing = {foo="bar", baz=5} + local str = require('variables_build')(thing) + assert.same(thing, load("return " ..str)()) end) it("allows for any values", function() local expected = {{pin=1,trigger=1},{pin=2,trigger=0}} - local str = variables_build.build(expected) - local result = loadstring("return " .. str)() + local str = require('variables_build')(expected) + local result = load("return " .. str)() assert.same(expected, result) end) + + it("allows for boolean and nil values", function() + local thing = {happy=true, tired=false, hungry=nil} + local str = require('variables_build')(thing) + assert.same(thing, load("return " ..str)()) + end) + + it("checks for nil", function() + local thing + local str = tostring(require('variables_build')(thing)) + assert.same(thing, load("return " ..str)()) + end) end) diff --git a/src/application.lua b/src/application.lua index f311225..1a78979 100644 --- a/src/application.lua +++ b/src/application.lua @@ -1,17 +1,13 @@ local sensors = require("sensors") local dht_sensors = require("dht_sensors") local actuators = require("actuators") -local smartthings = require("smartthings") +local settings = require("settings") local sensorSend = {} local dni = wifi.sta.getmac():gsub("%:", "") local timeout = tmr.create() local sensorTimer = tmr.create() local sendTimer = tmr.create() --- hack to ensure pin D8 stays low after boot so it can be used with a high-level trigger relay -gpio.mode(8, gpio.OUTPUT) -gpio.write(8, gpio.LOW) - timeout:register(10000, tmr.ALARM_SEMI, node.restart) for i, sensor in pairs(sensors) do @@ -35,12 +31,14 @@ if #dht_sensors > 0 then local humidity_string = humi .. "." .. humi_dec print("Heap:", node.heap(), "Temperature:", temperature_string, "Humidity:", humidity_string) table.insert(sensorSend, { pin = pin, temp = temperature_string, humi = humidity_string }) + else + print("Heap:", node.heap(), "DHT Status:", status) end end for i, sensor in pairs(dht_sensors) do - local pollInterval = (sensor.poll_interval or 3) * 60 * 1000 - print("Heap:", node.heap(), "Polling pin " .. sensor.pin .. " every " .. pollInterval .. "ms") + local pollInterval = (sensor.poll_interval > 0 and sensor.poll_interval or 3) * 60 * 1000 + print("Heap:", node.heap(), "Polling DHT on pin " .. sensor.pin .. " every " .. pollInterval .. "ms") tmr.create():alarm(pollInterval, tmr.ALARM_AUTO, function() readDht(sensor.pin) end) readDht(sensor.pin) end @@ -61,8 +59,8 @@ sendTimer:alarm(200, tmr.ALARM_AUTO, function(t) local sensor = sensorSend[1] timeout:start() http.put( - table.concat({ smartthings.apiUrl, "/device/", dni}), - table.concat({ "Authorization: Bearer ", smartthings.token, "\r\nAccept: application/json\r\nContent-Type: application/json\r\n" }), + table.concat({ settings.apiUrl, "/device/", dni}), + table.concat({ "Authorization: Bearer ", settings.token, "\r\nAccept: application/json\r\nContent-Type: application/json\r\n" }), sjson.encode(sensor), function(code) timeout:stop() @@ -79,3 +77,5 @@ sendTimer:alarm(200, tmr.ALARM_AUTO, function(t) collectgarbage() end end) + +print("Heap:", node.heap(), "Endpoint:", settings.apiUrl) \ No newline at end of file diff --git a/src/device.lua b/src/device.lua index 11cf2f4..36f030e 100644 --- a/src/device.lua +++ b/src/device.lua @@ -1,8 +1,8 @@ local me = { id = "uuid:8f655392-a778-4fee-97b9-4825918" .. string.format("%x", node.chipid()), name = "Konnected", - hwVersion = "2.2.0", - swVersion = "2.2.0", + hwVersion = "2.2.1", + swVersion = "2.2.1", http_port = math.floor(node.chipid()/1000) + 8000, urn = "urn:schemas-konnected-io:device:Security:1" } diff --git a/src/http_index.html.gz b/src/http_index.html.gz index 0c0eaf8..aab6320 100644 Binary files a/src/http_index.html.gz and b/src/http_index.html.gz differ diff --git a/src/init.lua b/src/init.lua index 6f14558..35d60a3 100644 --- a/src/init.lua +++ b/src/init.lua @@ -1,8 +1,12 @@ -print("Heap: ", node.heap(), "Initializing Konnected") +print("Heap: ", node.heap(), "Initializing Konnected (" .. string.gsub(wifi.sta.getmac(), ":", "") .. ")") require("start") print("Heap: ", node.heap(), "Version: ", require("device").swVersion) print("Heap: ", node.heap(), "Connecting to Wifi..") +-- hack to ensure pin D8 stays low after boot so it can be used with a high-level trigger relay +gpio.mode(8, gpio.OUTPUT) +gpio.write(8, gpio.LOW) + local startWifiSetup = function() print("Heap: ", node.heap(), "Entering Wifi setup mode") wifi.eventmon.unregister(wifi.eventmon.STA_DISCONNECTED) @@ -53,16 +57,12 @@ local _ = tmr.create():alarm(900, tmr.ALARM_AUTO, function(t) failsafeTimer = nil print("Heap: ", node.heap(), "Wifi connected with IP: ", wifi.sta.getip()) - if file.exists("update_init.lc") then - require("update") - else - gpio.write(4, gpio.HIGH) - enduser_setup.stop() - require("server") - print("Heap: ", node.heap(), "Loaded: ", "server") - require("application") - print("Heap: ", node.heap(), "Loaded: ", "application") - end + gpio.write(4, gpio.HIGH) + enduser_setup.stop() + require("server") + print("Heap: ", node.heap(), "Loaded: ", "server") + require("application") + print("Heap: ", node.heap(), "Loaded: ", "application") end end) diff --git a/src/manifest.json b/src/manifest.json index b5ae221..6e9490b 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,30 +1,27 @@ { "src/actuators.lua":"47a1a50c0c8cfb547554ded22a8134eaed76c0a3", - "src/application.lua":"f3112252f3548b49b16d0b8a8ae9cdc63da51a3a", - "src/device.lua":"11cf2f4d39cc86c2f19f071b4ec17d2f8b9be76f", + "src/application.lua":"c7d551eef59186f65d5d0845cd713bce549d2384", + "src/device.lua":"36f030ef89c2d33e08ece188ebfb36cf2a128ce1", "src/dht_sensors.lua":"0e931a0fea562883140a7f6f33ce8238424d263a", "src/enduser_setup.html.gz":"fbf730b33c309ceab15e88f162f43c232593f7da", "src/http_favicon.ico.gz":"483f371c590b0407c380d019bcc6938cf1d62f0a", - "src/http_index.html.gz":"0c0eaf8e051881d58484ab872e51a5a81f47c08d", + "src/http_index.html.gz":"aab63206d8ac1b0bd38c38f16b1c840114bef72b", "src/httpd_req.lua":"36ebc0d4fc8344f286ffa89deedde8e50d6aa718", "src/httpd_res.lua":"6c44401701ba0eafeb6f2cf175dff587cdb8105f", - "src/init.lua":"6f145587fef8616a5446a1e3f953789a0470278f", + "src/init.lua":"35d60a3ee41b6c3f13a732e4a079a1b1b328f9bb", "src/led_flip.lua":"590e7be1afe686f4213d097d0e9dba9e7a3910a0", - "src/manifest.json":"18fab37d2bb2c7270c816992e242292f51a8033a", + "src/manifest.json":"b5ae2213634af1ceb0295126822d3ba58bce3ea2", "src/sensors.lua":"d0d94fa73f713dcf2c517da9262f59f306b81d2b", "src/server.lua":"1649e94819773d6920b9e96d3ca5966c2a589189", "src/server_device.lua":"484441af8781b9b5a63f8807a14addda27ed5e99", "src/server_receiver.lua":"82d59d15042a181606a7437de9e919721f834f36", - "src/server_settings.lua":"adecc037cc4ae320e9bb47e147eafba9d4e3db70", - "src/server_status.lua":"e1dfab934475fef8fd16f51592f0a0ee3b632a14", + "src/server_settings.lua":"f7ae885866b6255a6f89251edbe20f278adb36b3", + "src/server_status.lua":"a88809b53238b1598c86b6706851eacfe6f918ff", "src/smartthings.lua":"ae11130360416aec5c2505c06850c5a4cd0449da", "src/ssdp.lua":"fb2088e9088f65757a7bec6304f688178b5e1cbe", "src/ssdp_response.lua":"9ff33e6dc7a6a190e19f9b2735146c9816db44c2", "src/start.lua":"af90c766d9afa65c6cbcddacb7ab91124b3598c6", - "src/update.lua":"5ac32ba8b3222399f1cddedd9584b6e72ff236dd", - "src/update_manifest.lua":"e3697f4f6ccd796771ec0de7f17709ad501cf2ae", - "src/update_process.lua":"b6ac63039a0edf5e816bcd17b44704f9deb6000d", "src/variables_build.lua":"b421b481a4f48ef68e063af0c2901e564d290f6a", "src/variables_set.lua":"a4f6a93151cbedf0bd5e533bf2ccfec96834edbd", - "updated_at":"2018-05-07:15:06:34" + "updated_at":"2018-06-14:18:10:32" } diff --git a/src/server.lua b/src/server.lua index 1649e94..daddc39 100644 --- a/src/server.lua +++ b/src/server.lua @@ -1,12 +1,14 @@ local device = require("device") -print("Heap: ", node.heap(), "UPnP: ", "Listening for UPnP discovery") -net.multicastJoin(wifi.sta.getip(), "239.255.255.250") -local upnp = net.createUDPSocket() -upnp:listen(1900, "0.0.0.0") -upnp:on("receive", function(c, d, port, ip) - require("ssdp_response")(c, d, port, ip) -end) +if require("settings").discovery ~= false then + print("Heap: ", node.heap(), "UPnP: ", "Listening for UPnP discovery") + net.multicastJoin(wifi.sta.getip(), "239.255.255.250") + local upnp = net.createUDPSocket() + upnp:listen(1900, "0.0.0.0") + upnp:on("receive", function(c, d, port, ip) + require("ssdp_response")(c, d, port, ip) + end) +end print("Heap: ", node.heap(), "HTTP: ", "Starting server at http://" .. wifi.sta.getip() .. ":" .. device.http_port) local http = net.createServer(net.TCP, 10) diff --git a/src/server_settings.lua b/src/server_settings.lua index adecc03..94a5cfa 100644 --- a/src/server_settings.lua +++ b/src/server_settings.lua @@ -4,16 +4,8 @@ restartTimer:register(2000, tmr.ALARM_SINGLE, function() node.restart() end) local function process(request) if request.method == "GET" then if request.query then - request.query.update = request.query.update or "false" - request.query.force = request.query.force or "false" - request.query.setfactory = request.query.setfactory or "false" request.query.restart = request.query.restart or "false" request.query.restore = request.query.restore or "false" - request.query.commitish = request.query.commitish or "master" - end - if request.query.update == "true" then - require("variables_set")("update_init", "{ force = "..request.query.force..", setfactory = "..request.query.setfactory..", commitish = \""..request.query.commitish.."\" }") - restartTimer:start() end if request.query.restart == "true" then restartTimer:start() @@ -27,12 +19,17 @@ local function process(request) if request.contentType == "application/json" then if request.method == "PUT" then local setVar = require("variables_set") - setVar("smartthings", table.concat({ "{ token = \"", request.body.token, "\",\r\n apiUrl = \"", request.body.apiUrl, "\" }" })) + setVar("settings", require("variables_build")({ + token = request.body.token, + apiUrl = request.body.apiUrl, + blink = request.body.blink, + discovery = request.body.discovery + })) setVar("sensors", require("variables_build")(request.body.sensors)) setVar("actuators", require("variables_build")(request.body.actuators)) setVar("dht_sensors", require("variables_build")(request.body.dht_sensors)) - print('Settings updated! Restarting in 5 seconds...') + print("Heap:", node.heap(), 'Settings updated! Restarting in 5 seconds...') restartTimer:start() return "" diff --git a/src/server_status.lua b/src/server_status.lua index e1dfab9..8c49cf6 100644 --- a/src/server_status.lua +++ b/src/server_status.lua @@ -15,7 +15,9 @@ local function process() mac = wifi.sta.getmac(), rssi = wifi.sta.getrssi(), sensors = require("sensors"), - actuators = require("actuators") + actuators = require("actuators"), + dht_sensors = require("dht_sensors"), + endpoint = require("settings").apiUrl } return sjson.encode(body) end diff --git a/src/settings.lua b/src/settings.lua new file mode 100644 index 0000000..4862b6b --- /dev/null +++ b/src/settings.lua @@ -0,0 +1,2 @@ +local settings = {} +return settings \ No newline at end of file diff --git a/src/smartthings.lua b/src/smartthings.lua deleted file mode 100644 index ae11130..0000000 --- a/src/smartthings.lua +++ /dev/null @@ -1,2 +0,0 @@ -local smartthings = {} -return smartthings \ No newline at end of file diff --git a/src/start.lua b/src/start.lua index af90c76..169a171 100644 --- a/src/start.lua +++ b/src/start.lua @@ -10,10 +10,14 @@ fn = nil gpio.mode(4, gpio.OUTPUT) -blinktimer = tmr.create() -blinktimer:register(100, tmr.ALARM_SEMI, function(t) - if gpio.read(4) == gpio.HIGH then - t:start() - end - require("led_flip").flip() -end) +if require("settings").blink ~= false then + blinktimer = tmr.create() + blinktimer:register(100, tmr.ALARM_SEMI, function(t) + if gpio.read(4) == gpio.HIGH then + t:start() + end + require("led_flip").flip() + end) +else + blinktimer = { start = function() end} +end diff --git a/src/update.lua b/src/update.lua deleted file mode 100644 index 5ac32ba..0000000 --- a/src/update.lua +++ /dev/null @@ -1,37 +0,0 @@ -print("Heap: ", node.heap(), "Updater: running..") -function findAttr(line) - local l1 = string.match(line, "http.*:\/\/(.*)") - local l2 = string.sub(l1, 1, (string.find(l1,"\/") - 1)) - local path = string.sub(l1, string.find(l1,"\/"), #l1) - local filenm = string.match(path, "\/.*\/(.*)") - local host, port = string.match(l2, "(.*):(.*)") - host = l2 or host - if string.match(line, "https:") then - port = "443" or port - elseif string.match(line, "http:") then - port = "80" or port - end - return host,port,path,filenm -end - -tmr.create():alarm(180, tmr.ALARM_AUTO, function(t) - if gpio.read(4) == gpio.HIGH then - gpio.write(4, gpio.LOW) - else - gpio.write(4, gpio.HIGH) - end -end) - -if file.exists("update_process.new") then - file.rename("update_process.new", "update_process.lua") - require("variables_set")("update_init", "{ force = true, commitish = \"v".. require("device").swVersion .. "\" }") - node.restart() -end - -if file.exists("manifest") then - require("update_process") -else - require("update_manifest") -end - - diff --git a/src/update_manifest.lua b/src/update_manifest.lua deleted file mode 100644 index e3697f4..0000000 --- a/src/update_manifest.lua +++ /dev/null @@ -1,113 +0,0 @@ -local device = require("device") -local update = require("update_init") -local repo = "konnected-io/konnected-security" -print("Heap: ", node.heap(), "Updater: Checking version") - -local download_new_manifest = function(tag_name) - http.get( - "https://github.com/" .. repo .. "/raw/" .. tag_name .. "/src/manifest.json", - "Accept-Encoding: deflate\r\n", - function(code, data) - local new_manifest = sjson.decode(data) - print("Heap: ", node.heap(), "downloaded updated manifest.json") - local file_size = file.list()['manifest.json'] - local current_manifest = {} - - -- open the existing manifest.json on the device for comparing file SHAs - if file.open("manifest.json") then - current_manifest = sjson.decode(file.read(file_size)) - file.close() - end - - -- open a new manifest temp file for writing - local fw = file.open("manifest", "w") - fw.writeline("manifest = { ") - - -- remove manifest.json and updated_at from manifest, these are special entries - new_manifest["src/manifest.json"] = nil - new_manifest["updated_at"] = nil - - for key, sha in pairs(new_manifest) do - if sha ~= current_manifest[key] then - print("Heap: ", node.heap(), "Needs update:", key) - local fname = string.match(key, '/([%w%p]+)$') - - fw.writeline(table.concat({ - "{ host = \"github.com\", port = \"443\", path = \"/", repo, "/raw/", - tag_name, "/", key, "\", filenm = \"", fname, "\", checksum = \"".. sha .."\" }," - })) - end - end - - -- always download the new manifest.json after everything else - fw.writeline(table.concat({ - "{ host = \"github.com\", port = \"443\", path = \"/", repo, "/raw/", - tag_name, "/src/manifest.json\", filenm = \"manifest.json\" }" - })) - fw.writeline("}") - fw.close() - collectgarbage() - print("Heap: ", node.heap(), "Updater:", "restarting in 3 seconds") - tmr.create():alarm(3000, tmr.ALARM_SINGLE, function() node.restart() end) - end - ) -end - -local compare_github_release = function(tag_name) - local restart = false - if tag_name then - local version = tag_name or device.swVersion - version = string.match(version, "[%d%.]+") - print("Heap: ", node.heap(), "Updater: Current version", device.swVersion) - print("Heap: ", node.heap(), "Updater: New version", version) - - if (version > device.swVersion) then - collectgarbage() - print("Heap: ", node.heap(), "Updater:", "Version outdated, retrieving manifest list") - tmr.create():alarm(1000, tmr.ALARM_SINGLE, function() download_new_manifest(tag_name) end) - else - print("Heap: ", node.heap(), "Updater:", "Software version up to date, cancelling update") - local fupdate = file.open("var_update.lua", "w") - fupdate:writeline("update = { run = false, force = false, setFactory = false }") - fupdate:close() - restart = true - end - else - print("Error connecting to GitHub") - restart = true - end - - if restart then - if file.exists("update_init.lua") then - file.remove("update_init.lua") - end - if file.exists("update_init.lc") then - file.remove("update_init.lc") - end - - print("Heap: ", node.heap(), "Updater:", "restarting in 3 seconds") - tmr.create():alarm(3000, tmr.ALARM_SINGLE, function() node.restart() end) - end -end - -local check_for_version_update = function() - http.get( - "https://api.github.com/repos/" .. repo .. "/releases/latest", - "Accept-Encoding: deflate\r\n", - function(code, data) - local latest_release_tag - if code == 200 then - latest_release_tag = sjson.decode(data)["tag_name"] - end - compare_github_release(latest_release_tag) - end - ) -end - -if update.force then - tag_name = update.commitish or 'master' - print("Heap: ", node.heap(), "Forcing software update to branch/tag: ", tag_name) - download_new_manifest(tag_name) -else - check_for_version_update() -end diff --git a/src/update_process.lua b/src/update_process.lua deleted file mode 100644 index b6ac630..0000000 --- a/src/update_process.lua +++ /dev/null @@ -1,164 +0,0 @@ -local proceed -local function getHeaderValue(line, headerPattern) - local l1 = string.match(line, "^" .. headerPattern .. ": (.*)") - if l1 then - local l2 = string.sub(l1, 1, ( string.find(l1, "\r\n") - 1 )) - return l2 - else - return nil - end -end - -dofile("manifest") -print("Heap: ", node.heap(), "Updater: Loaded manifest", #manifest) -tmr.create():alarm(200, tmr.ALARM_AUTO, function(t) - t:stop() - print("Heap: ", node.heap(), "Updater: Processing manifest", #manifest) - if manifest[1] then - proceed = true - - --do not overwrite user's sensors / actuators and smartthings info - if (manifest[1].filenm == "smartthings.lua" and file.exists("smartthings.lc")) or - (manifest[1].filenm == "sensors.lua" and file.exists("sensors.lc")) or - (manifest[1].filenm == "actuators.lua" and file.exists("actuators.lc")) then - proceed = false - print("Heap: ", node.heap(), "Updater: Skipping", manifest[1].filenm) - table.remove(manifest, 1) - end - - if proceed then - local fw = file.open(manifest[1].filenm .. ".tmp", "w") - local conn = net.createConnection(net.TCP, 1) - conn:connect(443, manifest[1].host) - conn:on("receive", function(sck, c) - print("Heap: ", node.heap(), "Updater: Downloading", manifest[1].filenm) - fw:write(c) - end) - conn:on("reconnection", function(sck, code) - print("Heap: ", node.heap(), "Updater: Disconnected with code", code) - end) - conn:on("disconnection", function(sck) - fw:close() - sck:close() - collectgarbage() - - local redirect = false - - local fr = file.open(manifest[1].filenm .. ".tmp", "r+") - local fr_line = "" - while true do - fr_line = fr:readline() - if fr_line == nil then - break - end - if string.find(fr_line, "^Status: 302") then - redirect = true - end - if redirect then - if string.match(fr_line, "^Location: (.*)") then - fr:seek("set", (fr:seek("cur") - #fr_line)) - fr_line = fr:read(1024) - local host, port, path = findAttr(getHeaderValue(fr_line, "Location")) - manifest[1] = { host = host, port = port, path = path, filenm = manifest[1].filenm, checksum = manifest[1].checksum } - print("Heap: ", node.heap(), "Updater: File redirection", manifest[1].filenm, "\r\nhttps:\/\/".. host .. path) - break - end - end - end - fr:close() - fr_line = nil - collectgarbage() - - if redirect == false then - print("Heap: ", node.heap(), "Updater: Downloaded", manifest[1].filenm) - - local fr_body_pos = 0 - local fr_line = "" - local fr_len = 0 - fr = file.open(manifest[1].filenm .. ".tmp", "r+") - print("Heap: ", node.heap(), "Updater: Processing file", manifest[1].filenm) - while true do - local fr_line = fr:readline() - if fr_line == nil then - break - end - - fr_len = getHeaderValue(fr_line, "Content%-Length") - if fr_len then - fr_body_pos = fr:seek("end") - string.format( "%d", fr_len ) - break - end - end - - fr_line = nil - collectgarbage() - - local fw = file.open(manifest[1].filenm .. ".bak.tmp", "w") - local checksum - - if crypto then - checksum = crypto.new_hash('SHA1') - -- this is some tricky Git magic: http://alblue.bandlem.com/2011/08/git-tip-of-week-objects.html - checksum:update("blob " .. fr_len .. "\0") - end - fr_len = nil - if fr_body_pos > 0 then - print("Heap: ", node.heap(), "Updater: Finalizing file", manifest[1].filenm) - while fr:seek("set", fr_body_pos) do - fr_body_pos = fr_body_pos + 512 - fr_line = fr:read(512) - fw:write(fr_line) - if crypto then checksum:update(fr_line) end - end - end - fr_line = nil - fr_body_pos = nil - fr:close() - fw:close() - collectgarbage() - file.remove(manifest[1].filenm .. ".tmp") - if file.exists(manifest[1].filenm) then file.remove(manifest[1].filenm) end - file.rename(manifest[1].filenm .. ".bak.tmp", manifest[1].filenm) - - if crypto and manifest[1].checksum then - if manifest[1].checksum == crypto.toHex(checksum:finalize()) then - print("Heap: ", node.heap(), "Updater: Checksums verified") - table.remove(manifest, 1) - else - print("Heap: ", node.heap(), "Updater: Checksums failed! Retrying ", manifest[1].filenm) - end - else - table.remove(manifest, 1) - end - end - - t:start() - end) - conn:on("connection", function(sck) - sck:send("GET " .. manifest[1].path .. " HTTP/1.1\r\nHost: ".. manifest[1].host .."\r\nConnection: close\r\n".. - "Accept: */*\r\nUser-Agent: ESP8266\r\n\r\n") - end) - else - t:start() - end - else - t:unregister() - if file.exists("update_init.lua") then - file.remove("update_init.lua") - end - if file.exists("update_init.lc") then - file.remove("update_init.lc") - end - if file.exists("manifest") then - file.remove("manifest") - end - if file.exists("device") then - file.rename("device", "device.lua") - end - print("Heap: ", node.heap(), "Updater: Done restarting in 3 seconds") - tmr.create():alarm(3000, tmr.ALARM_SINGLE, function(t) node.restart() end) - end -end) - - - diff --git a/src/variables_build.lua b/src/variables_build.lua index b421b48..82fffc7 100644 --- a/src/variables_build.lua +++ b/src/variables_build.lua @@ -1,21 +1,41 @@ local module = ... -local function build(objects) - if not objects then return nil end +local function build_list(objects) local out = {} - table.insert(out, "{ ") - for i, object in pairs(objects) do - table.insert(out, "\r\n{ ") - for key, value in pairs(object) do - table.insert(out, key .. " = " .. value .. ", ") + for key, value in pairs(objects) do + if type(value) == 'table' then + table.insert(out, "{") + table.insert(out, build_list(value)) + table.insert(out, "},") + else + table.insert(out, key) + table.insert(out, "=") + if type(value) == 'string' then + table.insert(out, "\"") + table.insert(out, value) + table.insert(out, "\"") + elseif type(value) == 'boolean' then + table.insert(out, tostring(value)) + else + table.insert(out, value) + end + table.insert(out, ",") end - table.insert(out, "},") end + return table.concat(out) +end + +local function build(objects) + if not objects then return nil end + local out = {} + table.insert(out, "{") + table.insert(out, build_list(objects)) table.insert(out, "}") return table.concat(out) end + return function(objects) package.loaded[module] = nil module = nil