diff --git a/Readme.md b/Readme.md index 751ac1d..36f3cf0 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,7 @@ # ESP Wordclock ## Setup +### Initial Setup Install the firmware on the ESP: The ESP must be set into the bootloader mode, like [this](https://www.ccc-mannheim.de/wiki/ESP8266#Boot_Modi) @@ -22,5 +23,12 @@ Then disconnect the serial terminal and copy the required files to the microcont ./tools/initialFlash.sh /dev/ttyUSB0 +### Upgrade + +Determine the IP address of your clock and execute the following script: +
+./tools/remoteFlash.sh IP-Address
+
+ ## Internal Setup * GPIO2 LEDs diff --git a/displayword.lua b/displayword.lua index c7fe7fe..113d205 100644 --- a/displayword.lua +++ b/displayword.lua @@ -85,15 +85,24 @@ function generateLEDs(words, colorForground, colorMin1, colorMin2, colorMin3, co minutes = minutes + 4 end data.charsPerMinute = round( (characters / minutes) ) - - -- devide by five (Minute 0, Minute 1 to Minute 4 takes the last chars) - print("Minutes : " .. tostring(minutes) .. " Char minutes: " .. tostring(data.charsPerMinute) ) + if (adc ~= nil) then + briPercent=(100*adc.read(0)/900) + print("Minutes : " .. tostring(minutes) .. " Char minutes: " .. tostring(data.charsPerMinute) .. " bright: " .. tostring(briPercent) .. "%") + data.colorFg = colorForground + data.colorMin1 = colorMin1 + data.colorMin2 = colorMin2 + data.colorMin3 = colorMin3 + data.colorMin4 = colorMin4 + else + -- devide by five (Minute 0, Minute 1 to Minute 4 takes the last chars) + print("Minutes : " .. tostring(minutes) .. " Char minutes: " .. tostring(data.charsPerMinute) ) + data.colorFg=colorForground + data.colorMin1=colorMin1 + data.colorMin2=colorMin2 + data.colorMin3=colorMin3 + data.colorMin4=colorMin4 + end data.words=words - data.colorFg=colorForground - data.colorMin1=colorMin1 - data.colorMin2=colorMin2 - data.colorMin3=colorMin3 - data.colorMin4=colorMin4 data.drawnCharacters=0 data.drawnWords=0 data.amountWords=display_countwords_de(words) diff --git a/index.html b/index.html index a6caac6..a938ea3 100644 --- a/index.html +++ b/index.html @@ -19,4 +19,4 @@
$ADDITIONAL_LINE - \ No newline at end of file + diff --git a/init.lua b/init.lua index 54c20bf..5a107f2 100644 --- a/init.lua +++ b/init.lua @@ -11,8 +11,9 @@ tmr.alarm(2, 85, 1, function() ws2812.write(string.char(128,0,0):rep(counter1) .. string.char(0,0,0):rep(spaceLeds) .. string.char(0,0,64):rep(counter1)) end) -local blacklistfile="init.lua config.lua config.lua.new" +local blacklistfile="init.lua config.lua config.lua.new webpage.html" function recompileAll() + for i=0,5 do tmr.stop(i) end -- compile all files l = file.list(); for k,_ in pairs(l) do @@ -43,7 +44,16 @@ end tmr.alarm(1, 5000, 0, function() tmr.stop(2) - if (file.open("main.lua")) then + if ( + (file.open("main.lua")) or + (file.open("timecore.lua")) or + (file.open("wordclock.lua")) or + (file.open("displayword.lua")) or + (file.open("webserver.lua")) + ) then + c = string.char(0,128,0) + w = string.char(0,0,0) + ws2812.write(w:rep(4) .. c .. w:rep(15) .. c .. w:rep(9) .. c .. w:rep(30) .. c .. w:rep(41) .. c ) recompileAll() print("Rebooting ...") -- reboot repairs everything diff --git a/os/0x00000.bin b/os/0x00000.bin index 19567c0..47bcfd4 100644 Binary files a/os/0x00000.bin and b/os/0x00000.bin differ diff --git a/os/0x10000.bin b/os/0x10000.bin index 20d0a8e..ac44e0e 100644 Binary files a/os/0x10000.bin and b/os/0x10000.bin differ diff --git a/os/Readme.md b/os/Readme.md index dccf967..c8a60f3 100644 --- a/os/Readme.md +++ b/os/Readme.md @@ -1,16 +1,20 @@ # Firmware was compiled with the following modules: - * LUA_USE_BUILTIN_STRING // for string.xxx() - * LUA_USE_BUILTIN_TABLE // for table.xxx() - * LUA_USE_BUILTIN_COROUTINE // for coroutine.xxx() - * LUA_USE_BUILTIN_MATH // for math.xxx(), partially work - * LUA_USE_BUILTIN_DEBUG_MINIMAL // for debug.getregistry() and debug.traceback() + * LUA_USE_MODULES_ADC + * LUA_USE_MODULES_BIT + * LUA_USE_MODULES_DHT * LUA_USE_MODULES_FILE * LUA_USE_MODULES_GPIO + * LUA_USE_MODULES_I2C + * LUA_USE_MODULES_MQTT * LUA_USE_MODULES_NET * LUA_USE_MODULES_NODE + * LUA_USE_MODULES_OW + * LUA_USE_MODULES_RTCFIFO + * LUA_USE_MODULES_RTCMEM * LUA_USE_MODULES_RTCTIME * LUA_USE_MODULES_SNTP + * LUA_USE_MODULES_SPI * LUA_USE_MODULES_TMR * LUA_USE_MODULES_UART * LUA_USE_MODULES_WIFI diff --git a/os/flash.sh b/os/flash.sh index 3a2fbb5..552208d 100755 --- a/os/flash.sh +++ b/os/flash.sh @@ -31,6 +31,6 @@ if [ $? -ne 0 ]; then echo "Error reading the MAC -> set the device into the bootloader!" exit 1 fi - -./esptool.py --port /dev/$DEVICE $BAUD write_flash -fm dio 0x00000 nodemcu2.bin 0x3fc000 esp_init_data_default.bin 0x07e000 blank.bin 0x3fe000 blank.bin -#./esptool.py --port /dev/$DEVICE $BAUD write_flash 0x00000 0x00000.bin 0x10000 0x10000.bin +echo "Flashing the new" +#./esptool.py --port /dev/$DEVICE $BAUD write_flash -fm dio 0x00000 nodemcu2.bin +./esptool.py --port /dev/$DEVICE $BAUD write_flash -fm dio 0x00000 0x00000.bin 0x10000 0x10000.bin 0x3fc000 esp_init_data_default.bin 0x07e000 blank.bin 0x3fe000 blank.bin diff --git a/simulation/Readme.md b/simulation/Readme.md index e897c86..1c1d3ff 100644 --- a/simulation/Readme.md +++ b/simulation/Readme.md @@ -1,5 +1,12 @@ # Simulation The simualation should be started with the following arguments at this position: - `../init.lua ws28128ClockLayout.txt config.lua` + `../init.lua ws28128ClockLayout.txt config.lua` +# Use it without Eclipse + +Compiling: + `javac -d bin/ -cp libs/luaj-jme-3.0.1.jar:libs/luaj-jse-3.0.1.jar $(find src -name '*.java')` + +Running: + `java -cp libs/luaj-jme-3.0.1.jar:libs/luaj-jse-3.0.1.jar:bin de.c3ma.ollo.WS2812Simulation ../init.lua ws28128ClockLayout.txt config.lua` diff --git a/tools/remoteFlash.sh b/tools/remoteFlash.sh new file mode 100755 index 0000000..c8d3446 --- /dev/null +++ b/tools/remoteFlash.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +IP=$1 + +FLASHTOOL=./tools/tcpFlash.py + +if [ ! -f $FLASHTOOL ]; then + echo "Execute the script in root folder of the project" + exit 2 +fi + +if [ "$IP" == "" ]; then + echo "IP address of ESP required" + echo "usage:" + echo "$0 " + echo "$0 192.168.0.2" + exit 1 +fi + +# check the connection +echo "Searching $IP ..." +ping $IP -c 2 >> /dev/null +if [ $? -ne 0 ]; then + echo "Entered IP address: $IP is NOT online" + exit 2 +fi +echo "Upgrading $IP" + +echo "stopWordclock()" > /tmp/wordClockCMD.txt +echo "uart.write(0, tostring(node.heap())" >> /tmp/wordClockCMD.txt +echo "c = string.char(0,0,128)" >> /tmp/wordClockCMD.txt +echo "w = string.char(0,0,0)" >> /tmp/wordClockCMD.txt +echo "ws2812.write(w:rep(4) .. c .. w:rep(15) .. c .. w:rep(9) .. c .. w:rep(30) .. c .. w:rep(41) .. c )" >> /tmp/wordClockCMD.txt +$FLASHTOOL -f /tmp/wordClockCMD.txt -t $IP -v + +FILES="displayword.lua main.lua timecore.lua webpage.html webserver.lua wordclock.lua init.lua" + +echo "Start Flasing ..." +for f in $FILES; do + if [ ! -f $f ]; then + echo "Cannot find $f" + echo "place the terminal into the folder where the lua files are present" + exit 1 + fi + echo "------------- $f ------------" + $FLASHTOOL -t $IP -f $f + if [ $? -ne 0 ]; then + echo "STOOOOP" + exit 1 + fi +done + +echo "TODO: Reboot the ESP" +#echo "node.restart()" | nc $IP 80 + +exit 0 diff --git a/tools/tcpFlash.py b/tools/tcpFlash.py new file mode 100755 index 0000000..2c32002 --- /dev/null +++ b/tools/tcpFlash.py @@ -0,0 +1,145 @@ +#!/usr/bin/python + +import argparse +import socket +import os.path +import sys #for exit and flushing of stdout +import time + +def sendRecv(s, message, answer): + msg = message + "\n" + s.sendall(msg) + reply = s.recv(4096) + i=1 + while ((not (answer in reply)) and (i < 10)): + reply += s.recv(4096) + i = i + 1 + if answer not in reply: + return False + else: + return True + +def sendCmd(s, message, cleaningEnter=False): + msg = message + "\n" + s.sendall(msg) + time.sleep(0.050) + reply = s.recv(4096) + i=1 + while ((not (">" in reply)) and (i < 10)): + time.sleep((0.050) * i) + reply += s.recv(4096) + i = i + 1 + +# print "Send\t" + message +# print "Got\t" + reply + if (cleaningEnter): + s.sendall("\n") + if "stdin:1:" in reply: + print "ERROR, received : " + reply + return False + elif ">" in reply: + return True + else: + print "ERROR, received : " + reply + return False + +def main(nodeip, luafile, volatile=None): + if ( not os.path.isfile(luafile) ): + print "The file " + luafile + " is not available" + else: + try: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect((nodeip, 80)) + time.sleep(0.050) + s.sendall("\n") + # Receive the hello Message of answer of the ESP + if (not sendRecv(s, "\n", "Welcome to ") ): + print "Cannot connect to the ESP" + s.close() + sys.exit(2) + + # Read all lines from the welcome message + i=0 + reply = s.recv(4096) + while ((reply is not None) and (not (">" in reply)) and (i < 100)): + reply = s.recv(4096) + i = i + 1 + + + # Communication tests + if ( not sendRecv(s, "print(12345)", "12345") ): + print "NOT communicating with an ESP8266 running LUA (nodemcu) firmware" + s.close() + sys.exit(3) + + sendCmd(s, "for i=0,5 do tmr.stop(i) end") + sendCmd(s, "collectgarbage()") + if (volatile is None): + print "Flashing " + luafile + sendCmd(s, "file.remove(\"" + luafile+"\");", True) + sendCmd(s, "w= file.writeline", True) + sendCmd(s, "file.open(\"" + luafile + "\",\"w+\");", True) + else: + print "Executing " + luafile + " on nodemcu" + + with open(luafile) as f: + contents = f.readlines() + i=1 + for line in contents: + print "\rSending " + str(i) + "/" + str(len(contents)) + " ...", + sys.stdout.flush() + l = line.rstrip() + if ( l.endswith("]") ): + l = l + " " + print "add a space at the end" + + if (volatile is None): + if (not sendCmd(s, "w([[" + l + "]]);")): + print "Cannot write line " + str(i) + s.close() + sys.exit(4) + else: + if (not sendCmd(s, l)): + print "Cannot write line " + str(i) + s.close() + sys.exit(4) + i=i+1 + + if (volatile is None): + # Finished with updating the file in LUA + if (not sendCmd(s, "w([[" + "--EOF" + "]]);")): + print "Cannot write line " + "-- EOF" + if (not sendCmd(s, "file.close();")): + print "Cannot close the file" + sys.exit(4) + + # Check if the file exists: + if (not sendRecv(s, "=file.exists(\"" + luafile + "\")", "true")): + print("Cannot send " + luafile + " to the ESP") + sys.exit(4) + else: + print("Updated " + luafile + " successfully") + else: + print("Send " + luafile + " successfully") + + # Cleaning the socket by closing it + s.close() + sys.exit(0) # Report that the flashing was succesfull + except socket.error, msg: + print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1] + sys.exit(1) + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('-t', '--target', help='IP address or dns of the ESP to flash') + parser.add_argument('-f', '--file', help='LUA file, that should be updated') + parser.add_argument('-v', '--volatile', help='File is executed at the commandline', action='store_const', const=1) + + args = parser.parse_args() + + if (args.target and args.file and args.volatile): + main(args.target, args.file, args.volatile) + elif (args.target and args.file): + main(args.target, args.file) + else: + parser.print_help() diff --git a/webpage.html b/webpage.html index fad40f7..2ba586a 100644 --- a/webpage.html +++ b/webpage.html @@ -45,8 +45,8 @@ Please note that all settings are mandatory

- - + + diff --git a/webserver.lua b/webserver.lua index 8568412..9ffba93 100644 --- a/webserver.lua +++ b/webserver.lua @@ -1,7 +1,7 @@ --TODO: - configFile="config.lua" +httpSending=false sentBytes=0 function sendPage(conn, nameOfFile, replaceMap) collectgarbage() @@ -11,8 +11,9 @@ function sendPage(conn, nameOfFile, replaceMap) conn:close() print("Page sent") collectgarbage() + httpSending=false else - print("Next") + collectgarbage() sendPage(conn, nameOfFile, replaceMap) end end) @@ -32,9 +33,6 @@ function sendPage(conn, nameOfFile, replaceMap) local line = file.readline() while (line ~= nil) do - -- increase the amount of sent bytes - sentBytes=sentBytes+string.len(line) - -- all placeholder begin with a $, so search for it in the current line if (line:find("$") ~= nil) then -- Replace the placeholder with the dynamic content @@ -45,10 +43,15 @@ function sendPage(conn, nameOfFile, replaceMap) end end end + + + -- increase the amount of sent bytes + sentBytes=sentBytes+string.len(line) + buf = buf .. line - -- Sent after 1k data - if (string.len(buf) >= 700) then + -- Sent after 500 bytes data + if ( (string.len(buf) >= 500) or (node.heap() < 2000) ) then line=nil conn:send(buf) print("Sent part of " .. sentBytes .. "B") @@ -62,10 +65,11 @@ function sendPage(conn, nameOfFile, replaceMap) --reset amount of sent bytes, as we reached the end sentBytes=0 -- send the rest - conn:send(buf) - print("Sent rest") + if (string.len(buf) > 0) then + conn:send(buf) + print("Sent rest") + end end - end function fillDynamicMap() @@ -121,21 +125,58 @@ function fillDynamicMap() return replaceMap end +function stopWordclock() + print("Stop all Wordclock") + -- Stop all + for i=0,5 do tmr.stop(i) end + -- unload all other functions + -- grep function *.lua | grep -v webserver | grep -v init.lua | grep -v main.lua | cut -f 2 -d ':' | grep "^function" | sed "s/function //g" | grep -o "^[a-zA-Z0-9\_]*" + updateColor = nil + drawLEDs = nil + round = nil + generateLEDs = nil + isSummerTime = nil + getUTCtime = nil + getTime = nil + display_timestat = nil + display_countcharacters_de = nil + display_countwords_de = nil + collectgarbage() +end + function startWebServer() srv=net.createServer(net.TCP) srv:listen(80,function(conn) conn:on("receive", function(conn,payload) - + if (httpSending) then + print("HTTP sending... be patient!") + return + end if (payload:find("GET /") ~= nil) then - --here is code for handling http request from a web-browser - + httpSending=true + stopWordclock() + if (color == nil) then + color=string.char(0,128,0) + end + ws2812.write(string.char(0,0,0):rep(56) .. color:rep(2) .. string.char(0,0,0):rep(4) .. color:rep(2) .. string.char(0,0,0):rep(48)) + -- Start Time after 3 minute + tmr.alarm(5, 180000, 0 ,function() + dependModules = { "timecore" , "wordclock", "displayword" } + for _,mod in pairs(dependModules) do + print("Loading " .. mod) + mydofile(mod) + end + -- Start the time Thread again + tmr.alarm(1, 20000, 1 ,function() + displayTime() + end) + end) if (sendPage ~= nil) then - print("Sending webpage.html ...") + print("Sending webpage.html (" .. tostring(node.heap()) .. "B free) ...") -- Load the sendPagewebcontent replaceMap=fillDynamicMap() sendPage(conn, "webpage.html", replaceMap) end - else if (payload:find("POST /") ~=nil) then --code for handling the POST-request (updating settings) _, postdatastart = payload:find("\r\n\r\n") @@ -165,8 +206,8 @@ function startWebServer() file.remove(configFile .. ".new") sec, _ = rtctime.get() file.open(configFile.. ".new", "w+") - file.write("-- Config\n" .. "station_cfg={}\nstation_cfg.ssid=\"" .. _POST.ssid .. "\"\nstation_cfg.pwd=\"" .. _POST.password .. "\"\nstation_cfg.save=false\nwifi.sta.config(station_cfg)\n") - file.write("sntpserverhostname=\"" .. _POST.sntpserver .. "\"\n" .. "timezoneoffset=\"" .. _POST.timezoneoffset .. "\"\n".. "inv46=\"" .. tostring(_POST.inv46) .. "\"\n") + file.write("-- Config\n" .. "station_cfg={}\nstation_cfg.ssid=\"" .. _POST.ssid .. "\"\nstation_cfg.pwd=\"" .. _POST.password .. "\"\nstation_cfg.save=false\nwifi.sta.config(station_cfg)\n") + file.write("sntpserverhostname=\"" .. _POST.sntpserver .. "\"\n" .. "timezoneoffset=\"" .. _POST.timezoneoffset .. "\"\n".. "inv46=\"" .. tostring(_POST.inv46) .. "\"\n") if ( _POST.fcolor ~= nil) then -- color=string.char(_POST.green, _POST.red, _POST.blue) @@ -279,19 +320,18 @@ function startWebServer() node.output(nil) global_c=nil end) - print("Welcome to Word Clock") - + print("Welcome to Word Clock") end end end) - conn:on("disconnection", function(c) print("Goodbye") node.output(nil) -- un-register the redirect output function, output goes to serial - + collectgarbage() --reset amount of sent bytes, as we reached the end sentBytes=0 end) end) end +--FileView done. diff --git a/wordclock.lua b/wordclock.lua index 3b5c021..f95b4c0 100755 --- a/wordclock.lua +++ b/wordclock.lua @@ -105,10 +105,10 @@ function display_timestat(hours, minutes, longmode) end if (hours == 1) then - if (ret.before == 1) then - ret.oneLong = 1 - else + if ((ret.it == 1) and (ret.half == 0) ) then ret.one=1 + else + ret.oneLong=1 end elseif (hours == 2) then ret.two=1
WIFI-SSIDSSID of the wireless network
WIFI-PasswordPassword of the wireless network
SNTP ServerServer to sync the time with. Only one ntp server is allowed.
Offset to UTC timeDefine the offset to UTC time in hours. For example +1 hour for Germany
SNTP ServerServer to sync the time with. Only one ntp server is allowed.
Offset to UTC timeDefine the offset to UTC time in hours. For example +1 hour for Germany
Foreground ColorLED Color for all minutes, divisible by five
Background ColorBackground LED Color
1. Minute ColorFirst minute after