initial commit
initial commit

 Binary files /dev/null and b/barometer-forecasting-table.jpg differ
file:b/config.lua (new)
--- /dev/null
+++ b/config.lua
@@ -1,1 +1,51 @@
+-- config.lua --
 
+serialDebug = true
+
+-- network
+wifiEnabled = true
+network = {}
+--network.ip = "192.168.0.51"
+--network.netmask = "255.255.255.0"
+--network.gateway = "192.168.0.1"
+
+-- MQTT
+prefix = "/iotcc"
+device = "/" .. wifi.sta.getmac() -- set the device as the wifi card mac address. Is unique, also easy to trace
+
+mqttConfig = {}
+mqttConfig.enabled = true
+mqttConfig.host = ''
+mqttConfig.port = ''
+mqttConfig.user = ''
+mqttConfig.pass = 'iot'
+mqttConfig.secure = 0
+mqttConfig.connected = false
+
+sData = {}
+sData.baro_qfe = 0
+sData.baro_qnh = 0
+sData.temperature = 0
+sData.humidity = 0
+sData.dew_point = 0
+sData.altitude = 0
+sData.pageName = "Weather stations"
+sData.pageId = 50
+sData.widget = "data"
+sData.title = "Summer kitchen temperature"
+sData.topic = prefix .. device ..'/ws1'
+sData.template = "template-1"
+sData.icon = "fa fa-thermometer-quarter"
+sData.class = "bg-green"
+sData.class2 = "text-center"
+sData.order = 10
+
+-- BME280
+sda, scl = 1, 2
+altitude = 81 -- altitude of the measurement place
+
+-- other
+deviceTitle = "Comana weather station"
+ntpserver = "194.177.34.116"
+timezoneHours = 2
+

file:b/func.lua (new)
--- /dev/null
+++ b/func.lua
@@ -1,1 +1,138 @@
+-- func.lua --
 
+-- setup SPI and connect display
+function init_spi_display()
+   -- Hardware SPI CLK  = GPIO14
+   -- Hardware SPI MOSI = GPIO13
+   -- Hardware SPI MISO = GPIO12 (not used)
+   -- Hardware SPI /CS  = GPIO15 (not used)
+   -- CS, D/C, and RES can be assigned freely to available GPIOs
+   local cs  = 8 -- GPIO15, pull-down 10k to GND
+   local dc  = 4 -- GPIO2
+   local res = 0 -- GPIO16
+
+   spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
+   -- we won't be using the HSPI /CS line, so disable it again
+   gpio.mode(8, gpio.INPUT, gpio.PULLUP)
+
+   -- initialize the matching driver for your display
+   disp = ucg.ili9341_18x240x320_hw_spi(cs, dc, res)
+end
+
+function getDateTime ()
+    tm = rtctime.epoch2cal(rtctime.get())
+    return string.format("%02d/%02d/%04d %02d:%02d",  tm["day"], tm["mon"], tm["year"], tm["hour"], tm["min"])
+end
+
+function lcdPrint(txt)
+    if serialDebug then print(txt) end
+    disp:setColor(255, 0, 0);
+    disp:drawBox(0, 210, 320, 20);
+    disp:setPrintPos(2, 225)
+    disp:setColor(255, 255, 255);
+    disp:setFont(ucg.font_7x13B_tr)
+    disp:print(txt)
+
+    tmr.stop(2)
+    tmr.alarm(2, 10000, 1, function()
+        disp:setColor(0, 0, 0);
+        disp:drawBox(0, 201, 320,30);
+        tmr.stop(2)
+    end)
+end
+
+function printText(text, font, x, y, r, g, b)
+    if font == 18 then
+        disp:setFont(ucg.font_helvB18_hr)
+    else
+        disp:setFont(ucg.font_helvB10_hr)
+    end
+    disp:setFontPosBottom()
+    local w = disp:getStrWidth(text)
+    local h = disp:getFontAscent() - disp:getFontDescent()
+    if x == nil then
+        x = ((disp:getWidth() - disp:getStrWidth(text)) / 2)
+    end
+    disp:setColor(0, 0, 0)
+    disp:drawBox(x, y-h, w, h)
+    disp:setColor(255, 255, 255)
+    disp:setPrintPos(x, y)
+    disp:print(text)
+end
+
+function update()
+    datetime = getDateTime()
+    lcdPrint("Update run at " .. datetime)
+
+    printText(datetime, 18, nil, 60)
+
+    H, T = bme280.humi()
+    if T and H then
+        local Tsgn = (T < 0 and -1 or 1); T = Tsgn*T
+        sData.temperature = string.format("%s%d.%02d", Tsgn<0 and "-" or "", T/100, T%100)
+        if serialDebug then print("Temperature=" .. sData.temperature) end
+        printText(sData.temperature .. " C", 18, 170, 90)
+
+        -- thermometer GradientBox
+        --disp:setColor(0, 0, 0)
+        --disp:drawBox(21, 94, 40, 100)
+        --disp:setColor(0, 255, 10, 0)
+        --disp:setColor(1, 255, 10, 0)
+        --disp:setColor(2, 5, 0, 255)
+        --disp:setColor(3, 5, 0, 255)
+        --local h = (20 + tonumber(sData.temperature)) * 1.42
+        --disp:drawGradientBox(21, 94 + 100 - h , 40, h)
+        --printText("-20", 10, 50, 192)
+        --printText("50", 10, 20, 70)
+
+        -- classic thermometer
+        local h = (20 + tonumber(sData.temperature)) * 1.71
+        disp:setColor(255, 255, 255);
+        disp:drawDisc(300, 170, 16, 15);
+        disp:drawRBox(290, 50, 20, 120, 8);
+        disp:setColor(255, 0, 0);
+        disp:drawDisc(300, 170, 10, 15);
+        disp:drawRBox(295, 55 + 120 - h, 10, h, 4);
+
+        sData.humidity = string.format("%d.%03d", H/1000, H%1000)
+        if serialDebug then print("Humidity=" .. sData.humidity) end
+        printText(sData.humidity .. " %", 18, 170, 120)
+
+        D = bme280.dewpoint(H, T)
+        local Dsgn = (D < 0 and -1 or 1); D = Dsgn*D
+        sData.dew_point = string.format("%s%d.%02d", Dsgn<0 and "-" or "", D/100, D%100)
+        if serialDebug then print("Dew point=" .. sData.dew_point) end
+    end
+    P, T = bme280.baro()
+    if P and T then
+        sData.baro_qfe = string.format("%d.%03d", P/1000, P%1000)
+        if serialDebug then print("QFE=" .. sData.baro_qfe) end
+
+        -- convert measure air pressure to sea level pressure
+        QNH = bme280.qfe2qnh(P, altitude)
+        sData.baro_qnh = string.format("%d.%03d", QNH/1000, QNH%1000)
+        if serialDebug then print("QNH=" .. sData.baro_qnh) end
+        printText(sData.baro_qnh, 18, 170, 150)
+    end
+        -- altimeter function - calculate altitude based on current sea level pressure (QNH) and measure pressure
+    P = bme280.baro()
+    if P then
+        curAlt = bme280.altitude(P, QNH)
+        local curAltsgn = (curAlt < 0 and -1 or 1); curAlt = curAltsgn*curAlt
+        sData.altitude = string.format("%s%d.%02d", curAltsgn<0 and "-" or "", curAlt/100, curAlt%100)
+        if serialDebug then print("Altitude=" .. sData.altitude) end
+    end
+
+    if mqttConfig.connected == true then
+        mqtt:publish(sData.topic .. "/config", sjson.encode(sData), 1, 0, function(conn)
+        end)
+    end
+end
+
+-- configure wifi reset button
+function pin3cb()
+    lcdPrint("Resetting wireless configuration and restarting")
+    node.restore()
+    node.restart()
+end
+

file:b/init.lua (new)
--- /dev/null
+++ b/init.lua
@@ -1,1 +1,111 @@
+-- init.lua --
 
+-- 10 seconds boot delay
+print("10 seconds boot delay. use tmr.stop(0) to stop booting")
+tmr.alarm(0, 10000, 1, function()
+    dofile("config.lua")
+    dofile("func.lua")
+    init()
+    tmr.stop(0)
+end)
+
+function init()
+    -- configure wifi reset button
+    gpio.trig(3, "down", pin3cb)
+    
+    -- initialize display
+    init_spi_display()
+    
+    disp:begin(ucg.FONT_MODE_TRANSPARENT)
+    disp:clearScreen()
+    disp:setRotate90()
+    
+    disp:setFont(ucg.font_helvB18_hr)
+    disp:setColor(255, 255, 255);
+    disp:setPrintPos((disp:getWidth() - disp:getStrWidth(deviceTitle)) / 2, 25)
+    disp:print(deviceTitle)
+
+    printText("Temperature", 18, 5, 90)
+    printText("Humidity", 18, 5, 120)
+    printText("Pressure", 18, 5, 150)
+    printText("50", 10, 292, 47)
+    printText("-20", 10, 290, 204)    
+    
+    --disp:drawFrame(20, 93, 42, 102)
+    
+    -- initialize BME280
+    i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once
+    bme280.setup()
+    
+    if wifiEnabled then
+        local def_sta_config=wifi.sta.getdefaultconfig(true)
+        if def_sta_config.ssid ~= "" then
+            lcdPrint(string.format("Found wifi config data in flash\n\tssid:\"%s\"\tpassword:\"%s\"%s", def_sta_config.ssid, def_sta_config.pwd, (type(def_sta_config.bssid)=="string" and "\tbssid:\""..def_sta_config.bssid.."\"" or "")))
+            wifi.sta.config(def_sta_config)
+            if network.ip ~= "" then
+                --wifi.sta.setip(network)
+            end
+        else
+            lcdPrint("No wifi config found on flash. Turning on IoT Setup")
+        end
+    
+        -- configure wifi via enduser setup
+        --wifi.setmode(wifi.STATIONAP)
+        --wifi.ap.config({ssid="IoTSetup_" .. wifi.sta.getmac(), auth=wifi.OPEN})
+        --enduser_setup.manual(true)
+        enduser_setup.start(
+            function()
+                do
+                    if network.ip ~= "" then
+                        --wifi.sta.setip(network)
+                    end
+                    tmr.stop(0)
+                    tmr.alarm(1, 3000, 1, function()
+                        if wifi.sta.getip()==nil then
+                            lcdPrint("\tConnected to access point, obtaining IP address ...")
+                        else
+                            def_sta_config=wifi.sta.getdefaultconfig(true)
+                            lcdPrint(string.format("\tConnected to access point ssid:\"%s\"\tpassword:\"%s\"%s", def_sta_config.ssid, def_sta_config.pwd, (type(def_sta_config.bssid)=="string" and "\tbssid:\""..def_sta_config.bssid.."\"" or "")))
+                            lcdPrint('\tip: ', wifi.sta.getip())
+                            --enduser_setup.stop()
+                            -- run the main file
+                            if file.exists("mqtt.lc") then
+                                dofile("mqtt.lc")
+                            else
+                                dofile("mqtt.lua")
+                            end
+                            tmr.stop(1)
+                        end
+                    end)
+                end
+            end,
+            function(err, str)
+                lcdPrint("enduser_setup: Err #" .. err .. ": " .. str)
+            end
+        );
+    
+        tmr.alarm(0, 3000, 1, function()
+            if wifi.sta.getip()==nil then
+                def_sta_config=wifi.sta.getdefaultconfig(true)
+                lcdPrint("Connecting to access point " .. def_sta_config.ssid)
+            else
+                tmr.stop(0)
+            end
+        end)
+    end
+    
+    -- run update at start
+    update()
+    
+    cron.reset()
+    cron.schedule("* * * * *", function(e)
+        print("----------------Every minute----------------")
+        update()
+    end)
+    
+    -- restart every hour
+    cron.schedule("1 * * * *", function(e)
+        --node.restart()
+    end)
+end
+

file:b/mqtt.lua (new)
--- /dev/null
+++ b/mqtt.lua
@@ -1,1 +1,60 @@
+-- mqtt.lua --
 
+-- initiate NTP sync
+sntp.sync(ntpserver,
+    function(sec, usec, server, info)
+        rtctime.set(sec + timezoneHours * 60 * 60, 0)
+        lcdPrint('NTP sync success! ' .. getDateTime())
+        update()
+    end,
+    function()
+        lcdPrint('NTP sync failed!')
+    end,
+    1
+)
+
+-- initiate the mqtt client and set keepalive timer to 120sec
+if mqttConfig.enabled == true then
+    mqtt = mqtt.Client(device, 120, mqttConfig.user, mqttConfig.pass, 1)
+
+    mqtt:on("connect", function(con)
+        lcdPrint("\tConnected to " .. mqttConfig.host .. ":" .. mqttConfig.port .. " MQTT broker\n")
+    end)
+    mqtt:on("offline", function(con)
+        lcdPrint("\tDisconected from " .. mqttConfig.host .. ":" .. mqttConfig.port .. " MQTT broker, reconnecting\n")
+        mqttConfig.connected = false
+    end)
+
+    -- on receive message
+    mqtt:on("message", function(conn, topic, message)
+        lcdPrint("\tReceived topic : " .. topic .. " / message : " .. message)
+
+        -- catch json errors
+        local ok, json = pcall(sjson.decode, message)
+        if ok then
+        else
+            lcdPrint("\tError parsing JSON : " .. message)
+            return
+        end
+
+        if topic == prefix .. "/device" then
+            lcdPrint('\tNew request from IoT Control Center: clientId="' .. json.clientId .. '"');
+            if json.time then
+                rtctime.set(json.time + timezoneHours * 60 * 60, 0)
+                update()
+            end
+            mqtt:publish(prefix .. device .. "/device", '{"pages" : [{"pageId" : 50, "pageName" : "Weather stations", "icon": "fa fa-thermometer-quarter"}]}', 1, 0, function(conn)
+            end)
+            update()
+        end
+    end)
+
+    mqtt:connect(mqttConfig.host, mqttConfig.port, mqttConfig.secure, function(conn)
+        lcdPrint("\tConnected to " .. mqttConfig.host .. ":" .. mqttConfig.port .. " MQTT broker\n")
+        mqttConfig.connected = true
+        -- subscribe topic with qos = 1
+        mqtt:subscribe({[prefix .. "/+/+/data"]=1, [prefix .. "/device"]=1}, function(conn)
+        end)
+    end)
+end
+

 Binary files /dev/null and b/wifiweatherstation.jpg differ
comments