Compare commits
88 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f79dd867c2 | ||
|
bc67988eea | ||
|
b597441192 | ||
|
061b4cff46 | ||
|
18e2f348a9 | ||
|
6d3f161b09 | ||
|
f5c3064773 | ||
|
93c6365ef8 | ||
|
3163148238 | ||
|
6813822f6d | ||
|
3a55addf66 | ||
|
8858bf2289 | ||
|
6621dee748 | ||
|
068f4b62e2 | ||
|
1051abbc45 | ||
|
24c5d23bef | ||
|
e485f2a0bd | ||
|
0085f9ae22 | ||
|
467530bec1 | ||
|
4be4e3fcee | ||
|
0ec3e0c159 | ||
|
e42edd7ccc | ||
|
542bd6613d | ||
|
2acd9af762 | ||
|
9adf5b9ed7 | ||
|
353e6f0117 | ||
|
fba6a90085 | ||
|
11bf35f22e | ||
|
b0d64e4140 | ||
|
cee1eeb6f3 | ||
|
84a36f2c6b | ||
|
4ee159cba3 | ||
|
a68f7571e7 | ||
|
1bbfb7feee | ||
|
38e591d061 | ||
|
4810985a54 | ||
|
b80a604b46 | ||
|
687a2bbbb9 | ||
|
d2ad06abf1 | ||
|
8aa34ce408 | ||
|
b99728ada6 | ||
|
60066bfca2 | ||
|
d1ad170955 | ||
|
3cb00ff3df | ||
|
7f0d578ca5 | ||
|
4b1cea0224 | ||
|
cdcd37a997 | ||
|
a20064bf61 | ||
|
093ab81c34 | ||
|
67c506571f | ||
|
8de86b065d | ||
|
a4eda884e3 | ||
|
dc8c5b5361 | ||
|
6e8a35307e | ||
|
eebe794df2 | ||
|
141b1b25d9 | ||
|
065caa4ddd | ||
|
28fca5989b | ||
|
28a5bdae85 | ||
|
10fa0b67a6 | ||
|
d166fb68df | ||
|
4ddbebd040 | ||
|
8321e5f112 | ||
|
b1f702df75 | ||
|
499cbcbbc5 | ||
|
1dc2530d38 | ||
|
d9f8d04f55 | ||
|
d25d3d55a7 | ||
|
1c0b5883b9 | ||
|
27ca03878c | ||
|
7140717696 | ||
|
6874d1545b | ||
|
58eed3bef5 | ||
|
4a97dbe0ca | ||
|
fc8ddab368 | ||
|
3e5327447b | ||
|
bab4c89d7b | ||
|
07852a6f25 | ||
|
c19d33d24f | ||
|
16b9675a4b | ||
|
0c8ab7155f | ||
|
b252453f1e | ||
|
309641c023 | ||
|
61c97d7a20 | ||
|
67434714ee | ||
|
53477902c2 | ||
|
c431d93895 | ||
|
1c7f3156ad |
22
Readme.md
22
Readme.md
@@ -1,11 +1,25 @@
|
|||||||
# ESP Wordclock
|
# ESP Wordclock
|
||||||
## Setup
|
## Setup
|
||||||
Generate a wlancfg.lua for your wifi based on the given example wlancfg.lua.example
|
|
||||||
|
|
||||||
Copy the required files to the microcontroller:
|
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)
|
||||||
|
|
||||||
|
The firmware can be downloaded with the following script:
|
||||||
<pre>
|
<pre>
|
||||||
sudo ./programESP.sh serial wlancfg.lua.lua wlancfg.lua
|
cd os/
|
||||||
sudo ./programESP.sh serial init.lua init.lua
|
./flash.sh ttyUSB0
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Reboot the ESP, with a serial terminal,
|
||||||
|
format the filesystem with the following command and reboot it:
|
||||||
|
<pre>
|
||||||
|
file.format()
|
||||||
|
node.reboot()
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Then disconnect the serial terminal and copy the required files to the microcontroller:
|
||||||
|
<pre>
|
||||||
|
./tools/initialFlash.sh /dev/ttyUSB0
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Internal Setup
|
## Internal Setup
|
||||||
|
222
displayword.lua
Normal file
222
displayword.lua
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
-- Module filling a buffer, sent to the LEDs
|
||||||
|
|
||||||
|
function updateColor(data)
|
||||||
|
if (data.usedCharacters <= data.charsPerMinute) then
|
||||||
|
if (data.words.min1 == 1 or data.words.min2 == 1 or data.words.min3 == 1 or data.words.min4 == 1) then
|
||||||
|
return data.colorMin1
|
||||||
|
else
|
||||||
|
return data.colorFg
|
||||||
|
end
|
||||||
|
elseif (data.usedCharacters <= data.charsPerMinute*2) then
|
||||||
|
if (data.words.min2 == 1 or data.words.min3 == 1 or data.words.min4 == 1) then
|
||||||
|
return data.colorMin2
|
||||||
|
else
|
||||||
|
return data.colorFg
|
||||||
|
end
|
||||||
|
elseif (data.usedCharacters <= data.charsPerMinute*3) then
|
||||||
|
if (data.words.min3 == 1 or data.words.min4 == 1) then
|
||||||
|
return data.colorMin3
|
||||||
|
else
|
||||||
|
return data.colorFg
|
||||||
|
end
|
||||||
|
elseif (data.usedCharacters > data.charsPerMinute*3) then
|
||||||
|
if (data.words.min4 == 1) then
|
||||||
|
return data.colorMin4
|
||||||
|
else
|
||||||
|
return data.colorFg
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return data.colorFg
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function drawLEDs(data, numberNewChars)
|
||||||
|
local tmpBuf=nil
|
||||||
|
for i=1,numberNewChars do
|
||||||
|
if (tmpBuf == nil) then
|
||||||
|
tmpBuf = updateColor(data)
|
||||||
|
else
|
||||||
|
tmpBuf=tmpBuf .. updateColor(data)
|
||||||
|
end
|
||||||
|
data.usedCharacters=data.usedCharacters+1
|
||||||
|
|
||||||
|
end
|
||||||
|
return tmpBuf
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Module displaying of the words
|
||||||
|
function generateLEDs(words, colorFg, colorMin1, colorMin2, colorMin3, colorMin4, characters)
|
||||||
|
-- Set the local variables needed for the colored progress bar
|
||||||
|
data={}
|
||||||
|
data.charsPerMinute=math.floor(characters/3) -- devide by three (Minute 1 to Minute 3, Minute 4 takes the last chars)
|
||||||
|
data.words=words
|
||||||
|
data.colorFg=colorFg
|
||||||
|
data.colorMin1=colorMin1
|
||||||
|
data.colorMin2=colorMin2
|
||||||
|
data.colorMin3=colorMin3
|
||||||
|
data.colorMin4=colorMin4
|
||||||
|
data.usedCharacters=0
|
||||||
|
local space=string.char(0,0,0)
|
||||||
|
-- update the background color, if set
|
||||||
|
if (colorBg ~= nil) then
|
||||||
|
space = colorBg
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set the foreground color as the default color
|
||||||
|
local buf=colorFg
|
||||||
|
|
||||||
|
-- line 1----------------------------------------------
|
||||||
|
if (words.itis == 1) then
|
||||||
|
buf=drawLEDs(data,2) -- ES
|
||||||
|
print(tostring(buf))
|
||||||
|
-- K fill character
|
||||||
|
buf=buf .. space:rep(1)
|
||||||
|
buf=buf .. drawLEDs(data,3) -- IST
|
||||||
|
-- L fill character
|
||||||
|
buf=buf .. space:rep(1)
|
||||||
|
else
|
||||||
|
buf=space:rep(7)
|
||||||
|
end
|
||||||
|
if (words.fiveMin== 1) then
|
||||||
|
buf= buf .. drawLEDs(data,4) -- FUENF
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(4)
|
||||||
|
end
|
||||||
|
-- line 2-- even row (so inverted) --------------------
|
||||||
|
if (words.twenty == 1) then
|
||||||
|
buf= buf .. drawLEDs(data,7) -- ZWANZIG
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(7)
|
||||||
|
end
|
||||||
|
if (words.tenMin == 1) then
|
||||||
|
buf= buf .. drawLEDs(data,4) -- ZEHN
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(4)
|
||||||
|
end
|
||||||
|
-- line3----------------------------------------------
|
||||||
|
if (words.threequater == 1) then
|
||||||
|
buf= buf .. drawLEDs(data,11) -- Dreiviertel
|
||||||
|
elseif (words.quater == 1) then
|
||||||
|
buf= buf .. space:rep(4)
|
||||||
|
buf= buf .. drawLEDs(data,7) -- VIERTEL
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(11)
|
||||||
|
end
|
||||||
|
--line 4-------- even row (so inverted) -------------
|
||||||
|
if (words.before == 1) then
|
||||||
|
buf=buf .. space:rep(2)
|
||||||
|
buf= buf .. drawLEDs(data,3) -- VOR
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(5)
|
||||||
|
end
|
||||||
|
if (words.after == 1) then
|
||||||
|
buf= buf .. drawLEDs(data,4) -- NACH
|
||||||
|
buf= buf .. space:rep(2) -- TG
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(6)
|
||||||
|
end
|
||||||
|
------------------------------------------------
|
||||||
|
if (words.half == 1) then
|
||||||
|
buf= buf .. drawLEDs(data,4) -- HALB
|
||||||
|
buf= buf .. space:rep(1) -- X
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(5)
|
||||||
|
end
|
||||||
|
if (words.twelve == 1) then
|
||||||
|
buf= buf .. drawLEDs(data,5) -- ZWOELF
|
||||||
|
buf= buf .. space:rep(1) -- P
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(6)
|
||||||
|
end
|
||||||
|
------------even row (so inverted) ---------------------
|
||||||
|
if (words.seven == 1) then
|
||||||
|
buf= buf .. drawLEDs(data,6) -- SIEBEN
|
||||||
|
buf= buf .. space:rep(5)
|
||||||
|
elseif (words.oneLong == 1) then
|
||||||
|
buf= buf .. space:rep(5)
|
||||||
|
buf= buf .. drawLEDs(data,4) -- EINS
|
||||||
|
buf= buf .. space:rep(2)
|
||||||
|
elseif (words.one == 1) then
|
||||||
|
buf= buf .. space:rep(6)
|
||||||
|
buf= buf .. drawLEDs(data,3) -- EIN
|
||||||
|
buf= buf .. space:rep(2)
|
||||||
|
elseif (words.two == 1) then
|
||||||
|
buf= buf .. space:rep(7)
|
||||||
|
buf= buf .. drawLEDs(data,4) -- ZWEI
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(11)
|
||||||
|
end
|
||||||
|
------------------------------------------------
|
||||||
|
if (words.three == 1) then
|
||||||
|
buf= buf .. space:rep(1)
|
||||||
|
buf= buf .. drawLEDs(data,4) -- DREI
|
||||||
|
buf= buf .. space:rep(6)
|
||||||
|
elseif (words.five == 1) then
|
||||||
|
buf= buf .. space:rep(7)
|
||||||
|
buf= buf .. drawLEDs(data,4) -- FUENF
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(11)
|
||||||
|
end
|
||||||
|
------------even row (so inverted) ---------------------
|
||||||
|
if (words.four == 1) then
|
||||||
|
buf= buf .. drawLEDs(data,4) -- VIER
|
||||||
|
buf= buf .. space:rep(7)
|
||||||
|
elseif (words.nine == 1) then
|
||||||
|
buf= buf .. space:rep(4)
|
||||||
|
buf= buf .. drawLEDs(data,4) -- NEUN
|
||||||
|
buf= buf .. space:rep(3)
|
||||||
|
elseif (words.eleven == 1) then
|
||||||
|
buf= buf .. space:rep(8)
|
||||||
|
buf= buf .. drawLEDs(data,3) -- ELEVEN
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(11)
|
||||||
|
end
|
||||||
|
------------------------------------------------
|
||||||
|
if (words.eight == 1) then
|
||||||
|
buf= buf .. space:rep(1)
|
||||||
|
buf= buf .. drawLEDs(data,4) -- ACHT
|
||||||
|
buf= buf .. space:rep(6)
|
||||||
|
elseif (words.ten == 1) then
|
||||||
|
buf= buf .. space:rep(5)
|
||||||
|
buf= buf .. drawLEDs(data,4) -- ZEHN
|
||||||
|
buf= buf .. space:rep(2)
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(11)
|
||||||
|
end
|
||||||
|
------------even row (so inverted) ---------------------
|
||||||
|
if (words.clock == 1) then
|
||||||
|
buf= buf .. drawLEDs(data,3) -- UHR
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(3)
|
||||||
|
end
|
||||||
|
if (words.six == 1) then
|
||||||
|
buf= buf .. space:rep(2)
|
||||||
|
buf= buf .. drawLEDs(data,5) -- SECHS
|
||||||
|
buf= buf .. space:rep(1)
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(8)
|
||||||
|
end
|
||||||
|
|
||||||
|
if (words.min1 == 1) then
|
||||||
|
buf= buf .. colorFg
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(1)
|
||||||
|
end
|
||||||
|
if (words.min2 == 1) then
|
||||||
|
buf= buf .. colorFg
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(1)
|
||||||
|
end
|
||||||
|
if (words.min3 == 1) then
|
||||||
|
buf= buf .. colorFg
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(1)
|
||||||
|
end
|
||||||
|
if (words.min4 == 1) then
|
||||||
|
buf= buf .. colorFg
|
||||||
|
else
|
||||||
|
buf= buf .. space:rep(1)
|
||||||
|
end
|
||||||
|
collectgarbage()
|
||||||
|
return buf
|
||||||
|
end
|
22
index.html
Normal file
22
index.html
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<html>
|
||||||
|
<head><title>WordClock Setup Page</title>
|
||||||
|
</head><body>
|
||||||
|
<h1>Welcome to the WordClock</h1>
|
||||||
|
<form action="" method="POST">
|
||||||
|
<table>
|
||||||
|
<tr><th>WIFI-SSID</b></th><td><input name="ssid" value="${SSID}"></td><td /></tr>
|
||||||
|
<tr><th>WIFI-Password</th><td><input name="password"></td><td /></tr>
|
||||||
|
<tr><th>SNTP Server</th><td><input name="sntpserver" value="${sntpserverhostname}" ></td><td>ntp server to sync the time</tr>
|
||||||
|
<tr><th>Offset to UTC time</th><td><input type="number" name="timezoneoffset" value="${TIMEZONEOFFSET}"></td><td>Define the offset to UTC time in hours. E.g +1</tr>
|
||||||
|
<tr><th>Color</th><td><input type="color" name="fcolor" value="${HEXCOLOR}"></td><td /></tr>
|
||||||
|
<tr><th>1. Minute Color</th><td><input type=\"color\" name=\"colorMin1\" value=\"" .. hexColor1 .. "\"></td><td /></tr>"
|
||||||
|
<tr><th>2. Minute Color</th><td><input type=\"color\" name=\"colorMin2\" value=\"" .. hexColor2 .. "\"></td><td /></tr>"
|
||||||
|
<tr><th>3. Minute Color</th><td><input type=\"color\" name=\"colorMin3\" value=\"" .. hexColor3 .. "\"></td><td /></tr>"
|
||||||
|
<tr><th>4. Minute Color</th><td><input type=\"color\" name=\"colorMin4\" value=\"" .. hexColor4 .. "\"></td><td /></tr>"
|
||||||
|
<tr><th>Three quater</th><td><input type="checkbox" name="threequater" ${THREEQUARTERCHECKED}></td><td>Dreiviertel Joa/nei</td></tr>
|
||||||
|
<tr><th>ColorMode</th><td><input type="checkbox" name="colorMode" ${COLORMODECHECKED}></td><td>If checked, words are dark, rest is colored</td></tr>
|
||||||
|
<tr><td colspan="3"><div align="center"><input type="submit" value="Save Configuration" onclick="this.value='Submitting ..';this.disabled='disabled'; this.form.submit();"></div></td></tr>
|
||||||
|
<tr><td colspan="3"><div align="center"><input type="submit" name="action" value="Reboot"></div></td></tr>
|
||||||
|
</table></form>
|
||||||
|
$ADDITIONAL_LINE
|
||||||
|
</body></html>
|
56
init.lua
Normal file
56
init.lua
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
uart.setup(0, 115200, 8, 0, 1, 1 )
|
||||||
|
print("Autostart in 5 seconds...")
|
||||||
|
|
||||||
|
ws2812.init() -- WS2812 LEDs initialized on GPIO2
|
||||||
|
MAXLEDS=110
|
||||||
|
counter1=0
|
||||||
|
ws2812.write(string.char(0,0,0):rep(114))
|
||||||
|
tmr.alarm(2, 85, 1, function()
|
||||||
|
counter1=counter1+1
|
||||||
|
ws2812.write(string.char(128,0,0):rep(counter1) .. string.char(0,0,0):rep(MAXLEDS - (counter1*2)) .. string.char(0,0,64):rep(counter1))
|
||||||
|
end)
|
||||||
|
|
||||||
|
local blacklistfile="init.lua config.lua config.lua.new"
|
||||||
|
function recompileAll()
|
||||||
|
-- compile all files
|
||||||
|
l = file.list();
|
||||||
|
for k,_ in pairs(l) do
|
||||||
|
if (string.find(k, ".lc", -3)) then
|
||||||
|
print ("Skipping " .. k)
|
||||||
|
elseif (string.find(blacklistfile, k) == nil) then
|
||||||
|
-- Only look at lua files
|
||||||
|
if (string.find(k, ".lua") ~= nil) then
|
||||||
|
print("Compiling and deleting " .. k)
|
||||||
|
node.compile(k)
|
||||||
|
-- remove the lua file
|
||||||
|
file.remove(k)
|
||||||
|
else
|
||||||
|
print("No code: " .. k)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mydofile(mod)
|
||||||
|
if (file.open(mod .. ".lua")) then
|
||||||
|
dofile( mod .. ".lua")
|
||||||
|
else
|
||||||
|
dofile(mod .. ".lc")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
tmr.alarm(1, 5000, 0, function()
|
||||||
|
tmr.stop(2)
|
||||||
|
if (file.open("main.lua")) then
|
||||||
|
recompileAll()
|
||||||
|
print("Rebooting ...")
|
||||||
|
-- reboot repairs everything
|
||||||
|
node.restart()
|
||||||
|
elseif (file.open("main.lc")) then
|
||||||
|
print("Starting main")
|
||||||
|
dofile("main.lc")
|
||||||
|
else
|
||||||
|
print("No Main file found")
|
||||||
|
end
|
||||||
|
end)
|
146
main.lua
Normal file
146
main.lua
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
-- Main Module
|
||||||
|
|
||||||
|
function startSetupMode()
|
||||||
|
tmr.stop(0)
|
||||||
|
tmr.stop(1)
|
||||||
|
-- start the webserver module
|
||||||
|
mydofile("webserver")
|
||||||
|
|
||||||
|
wifi.setmode(wifi.SOFTAP)
|
||||||
|
cfg={}
|
||||||
|
cfg.ssid="wordclock"
|
||||||
|
cfg.pwd="wordclock"
|
||||||
|
wifi.ap.config(cfg)
|
||||||
|
|
||||||
|
-- Write the buffer to the LEDs
|
||||||
|
local color=string.char(0,128,0)
|
||||||
|
local white=string.char(0,0,0)
|
||||||
|
local ledBuf= white:rep(6) .. color .. white:rep(7) .. color:rep(3) .. white:rep(44) .. color:rep(3) .. white:rep(50)
|
||||||
|
ws2812.write(ledBuf)
|
||||||
|
color=nil
|
||||||
|
white=nil
|
||||||
|
ledBuf=nil
|
||||||
|
|
||||||
|
print("Waiting in access point >wordclock< for Clients")
|
||||||
|
print("Please visit 192.168.4.1")
|
||||||
|
startWebServer()
|
||||||
|
collectgarbage()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function syncTimeFromInternet()
|
||||||
|
--ptbtime1.ptb.de
|
||||||
|
sntp.sync(sntpserverhostname,
|
||||||
|
function(sec,usec,server)
|
||||||
|
print('sync', sec, usec, server)
|
||||||
|
displayTime()
|
||||||
|
end,
|
||||||
|
function()
|
||||||
|
print('failed!')
|
||||||
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
function displayTime()
|
||||||
|
sec, usec = rtctime.get()
|
||||||
|
-- Handle lazy programmer:
|
||||||
|
if (timezoneoffset == nil) then
|
||||||
|
timezoneoffset=0
|
||||||
|
end
|
||||||
|
time = getTime(sec, timezoneoffset)
|
||||||
|
words = display_timestat(time.hour, time.minute)
|
||||||
|
|
||||||
|
local charactersOfTime = display_countwords_de(words)
|
||||||
|
ledBuf = generateLEDs(words, color, color1, color2, color3, color4,
|
||||||
|
charactersOfTime)
|
||||||
|
|
||||||
|
print("Local time : " .. time.year .. "-" .. time.month .. "-" .. time.day .. " " .. time.hour .. ":" .. time.minute .. ":" .. time.second .. " in " .. charactersOfTime .. " chars")
|
||||||
|
|
||||||
|
-- Write the buffer to the LEDs
|
||||||
|
ws2812.write(ledBuf)
|
||||||
|
|
||||||
|
-- Used for debugging
|
||||||
|
if (clockdebug ~= nil) then
|
||||||
|
for key,value in pairs(words) do
|
||||||
|
if (value > 0) then
|
||||||
|
print(key,value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- cleanup
|
||||||
|
ledBuf=nil
|
||||||
|
words=nil
|
||||||
|
time=nil
|
||||||
|
collectgarbage()
|
||||||
|
end
|
||||||
|
|
||||||
|
function normalOperation()
|
||||||
|
-- use default color, if nothing is defined
|
||||||
|
if (color == nil) then
|
||||||
|
-- Color is defined as GREEN, RED, BLUE
|
||||||
|
color=string.char(0,0,250)
|
||||||
|
end
|
||||||
|
|
||||||
|
connect_counter=0
|
||||||
|
-- Wait to be connect to the WiFi access point.
|
||||||
|
tmr.alarm(0, 1000, 1, function()
|
||||||
|
connect_counter=connect_counter+1
|
||||||
|
if wifi.sta.status() ~= 5 then
|
||||||
|
print(connect_counter .. "/60 Connecting to AP...")
|
||||||
|
if (connect_counter % 2 == 0) then
|
||||||
|
local wlanColor=string.char((connect_counter % 6)*20,(connect_counter % 5)*20,(connect_counter % 3)*20)
|
||||||
|
local space=string.char(0,0,0)
|
||||||
|
local buf=space:rep(6) .. wlanColor .. space:rep(4)
|
||||||
|
buf= buf .. space:rep(3) .. wlanColor:rep(3)
|
||||||
|
ws2812.write(buf)
|
||||||
|
else
|
||||||
|
ws2812.write(string.char(0,0,0):rep(114))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
tmr.stop(0)
|
||||||
|
print('IP: ',wifi.sta.getip())
|
||||||
|
-- Here the WLAN is found, and something is done
|
||||||
|
print("Solving dependencies")
|
||||||
|
local dependModules = { "timecore" , "wordclock", "displayword" }
|
||||||
|
for _,mod in pairs(dependModules) do
|
||||||
|
print("Loading " .. mod)
|
||||||
|
mydofile(mod)
|
||||||
|
end
|
||||||
|
|
||||||
|
tmr.alarm(2, 500, 0 ,function()
|
||||||
|
syncTimeFromInternet()
|
||||||
|
end)
|
||||||
|
tmr.alarm(3, 2000, 0 ,function()
|
||||||
|
print("Start webserver...")
|
||||||
|
mydofile("webserver")
|
||||||
|
startWebServer()
|
||||||
|
end)
|
||||||
|
|
||||||
|
displayTime()
|
||||||
|
-- Start the time Thread
|
||||||
|
tmr.alarm(1, 20000, 1 ,function()
|
||||||
|
displayTime()
|
||||||
|
end)
|
||||||
|
|
||||||
|
end
|
||||||
|
-- when no wifi available, open an accesspoint and ask the user
|
||||||
|
if (connect_counter >= 60) then -- 300 is 30 sec in 100ms cycle
|
||||||
|
startSetupMode()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------main program -----------------------------
|
||||||
|
ws2812.init() -- WS2812 LEDs initialized on GPIO2
|
||||||
|
|
||||||
|
if ( file.open("config.lua") ) then
|
||||||
|
--- Normal operation
|
||||||
|
wifi.setmode(wifi.STATION)
|
||||||
|
dofile("config.lua")
|
||||||
|
normalOperation()
|
||||||
|
else
|
||||||
|
-- Logic for inital setup
|
||||||
|
startSetupMode()
|
||||||
|
end
|
31
ntpTest.lua
31
ntpTest.lua
@@ -1,31 +0,0 @@
|
|||||||
dofile("wlancfg.lua")
|
|
||||||
|
|
||||||
-- Wait to be connect to the WiFi access point.
|
|
||||||
tmr.alarm(0, 100, 1, function()
|
|
||||||
if wifi.sta.status() ~= 5 then
|
|
||||||
print("Connecting to AP...")
|
|
||||||
else
|
|
||||||
tmr.stop(0)
|
|
||||||
-- Switch of the booting lamp
|
|
||||||
gpio.write(5, gpio.LOW)
|
|
||||||
print('IP: ',wifi.sta.getip())
|
|
||||||
|
|
||||||
--ptbtime1.ptb.de
|
|
||||||
sntp.sync('192.53.103.108',
|
|
||||||
function(sec,usec,server)
|
|
||||||
print('sync', sec, usec, server)
|
|
||||||
end,
|
|
||||||
function()
|
|
||||||
print('failed!')
|
|
||||||
end
|
|
||||||
)
|
|
||||||
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
tmr.alarm(1, 1000, 1 ,function()
|
|
||||||
sec, usec = rtctime.get()
|
|
||||||
print("Time : " , sec)
|
|
||||||
end)
|
|
||||||
|
|
BIN
os/0x00000.bin
BIN
os/0x00000.bin
Binary file not shown.
BIN
os/0x10000.bin
BIN
os/0x10000.bin
Binary file not shown.
18
os/Readme.md
Normal file
18
os/Readme.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# 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_FILE
|
||||||
|
* LUA_USE_MODULES_GPIO
|
||||||
|
* LUA_USE_MODULES_NET
|
||||||
|
* LUA_USE_MODULES_NODE
|
||||||
|
* LUA_USE_MODULES_RTCTIME
|
||||||
|
* LUA_USE_MODULES_SNTP
|
||||||
|
* LUA_USE_MODULES_TMR
|
||||||
|
* LUA_USE_MODULES_UART
|
||||||
|
* LUA_USE_MODULES_WIFI
|
||||||
|
* LUA_USE_MODULES_WS2812
|
||||||
|
|
@@ -9,6 +9,8 @@ if [ $# -ne 1 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
DEVICE=$1
|
DEVICE=$1
|
||||||
|
#BAUD="--baud 57600"
|
||||||
|
#BAUD="--baud 921600"
|
||||||
|
|
||||||
# check the serial connection
|
# check the serial connection
|
||||||
|
|
||||||
@@ -23,11 +25,12 @@ if [ ! -f esptool.py ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sudo ./esptool.py --port /dev/$DEVICE read_mac
|
./esptool.py --port /dev/$DEVICE $BAUD read_mac
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "Error reading the MAC -> set the device into the bootloader!"
|
echo "Error reading the MAC -> set the device into the bootloader!"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sudo ./esptool.py --port /dev/$DEVICE write_flash 0x00000 0x00000.bin 0x10000 0x10000.bin
|
#./esptool.py --port /dev/$DEVICE $BAUD write_flash 0x00000 nodemcu-master-enduser_setup,file,gpio,net,node,rtcfifo,rtcmem,rtctime,sntp,spi,tmr,uart,wifi,ws2812-integer.bin
|
||||||
|
./esptool.py --port /dev/ttyUSB0 $BAUD write_flash 0x00000 0x00000.bin 0x10000 0x10000.bin
|
||||||
|
16
timecore.lua
Normal file → Executable file
16
timecore.lua
Normal file → Executable file
@@ -56,13 +56,13 @@ end
|
|||||||
-- Source:
|
-- Source:
|
||||||
-- http://www.jbox.dk/sanos/source/lib/time.c.html
|
-- http://www.jbox.dk/sanos/source/lib/time.c.html
|
||||||
|
|
||||||
YEAR0=1900
|
local YEAR0=1900
|
||||||
|
|
||||||
EPOCH_YR=1970
|
local EPOCH_YR=1970
|
||||||
--SECS_DAY=(24L * 60L * 60L)
|
--SECS_DAY=(24L * 60L * 60L)
|
||||||
SECS_DAY=86400
|
local SECS_DAY=86400
|
||||||
|
|
||||||
ytab = {}
|
local ytab = {}
|
||||||
ytab[0] = {}
|
ytab[0] = {}
|
||||||
ytab[1] = {}
|
ytab[1] = {}
|
||||||
ytab[0][0] = 31
|
ytab[0][0] = 31
|
||||||
@@ -106,7 +106,7 @@ end
|
|||||||
function getUTCtime(unixtimestmp)
|
function getUTCtime(unixtimestmp)
|
||||||
local year = EPOCH_YR
|
local year = EPOCH_YR
|
||||||
local dayclock = math.floor(unixtimestmp % SECS_DAY)
|
local dayclock = math.floor(unixtimestmp % SECS_DAY)
|
||||||
dayno = math.floor(unixtimestmp / SECS_DAY)
|
local dayno = math.floor(unixtimestmp / SECS_DAY)
|
||||||
|
|
||||||
local sec = math.floor(dayclock % 60)
|
local sec = math.floor(dayclock % 60)
|
||||||
local min = math.floor( (dayclock % 3600) / 60)
|
local min = math.floor( (dayclock % 3600) / 60)
|
||||||
@@ -119,20 +119,20 @@ function getUTCtime(unixtimestmp)
|
|||||||
year=year + 1
|
year=year + 1
|
||||||
end
|
end
|
||||||
--Day in whole year: local yday = dayno (Not needed)
|
--Day in whole year: local yday = dayno (Not needed)
|
||||||
mon = 0
|
local mon = 0
|
||||||
while (dayno >= ytab[leapyear(year) and 1 or 0][mon])
|
while (dayno >= ytab[leapyear(year) and 1 or 0][mon])
|
||||||
do
|
do
|
||||||
dayno = dayno - ytab[leapyear(year) and 1 or 0][mon];
|
dayno = dayno - ytab[leapyear(year) and 1 or 0][mon];
|
||||||
mon = mon + 1
|
mon = mon + 1
|
||||||
end
|
end
|
||||||
mday = dayno + 1
|
local mday = dayno + 1
|
||||||
|
|
||||||
return { year = year, month = (mon+1), day = mday, hour = hour, minute = min, second = sec, dow = dow }
|
return { year = year, month = (mon+1), day = mday, hour = hour, minute = min, second = sec, dow = dow }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function getTime(unixtimestmp, timezoneoffset)
|
function getTime(unixtimestmp, timezoneoffset)
|
||||||
time = getUTCtime(unixtimestmp + (3600 * timezoneoffset))
|
local time = getUTCtime(unixtimestmp + (3600 * timezoneoffset))
|
||||||
if ( isSummerTime(time) ) then
|
if ( isSummerTime(time) ) then
|
||||||
time = getUTCtime(unixtimestmp + (3600 * (timezoneoffset + 1)) )
|
time = getUTCtime(unixtimestmp + (3600 * (timezoneoffset + 1)) )
|
||||||
end
|
end
|
||||||
|
2
tools/Readme.md
Normal file
2
tools/Readme.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Source:
|
||||||
|
https://github.com/4refr0nt/luatool/tree/master/luatool
|
49
tools/initialFlash.sh
Executable file
49
tools/initialFlash.sh
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
LUATOOL=./tools/luatool.py
|
||||||
|
|
||||||
|
DEVICE=$1
|
||||||
|
|
||||||
|
# check the serial connection
|
||||||
|
|
||||||
|
if [ ! -c $DEVICE ]; then
|
||||||
|
echo "$DEVICE does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
echo ""
|
||||||
|
echo "e.g. usage $0 <device>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
FILES="displayword.lua main.lua timecore.lua webpage.lua webserver.lua wordclock.lua init.lua"
|
||||||
|
# Format filesystem first
|
||||||
|
echo "Format the complete ESP"
|
||||||
|
$LUATOOL -p $DEVICE -w
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "STOOOOP"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
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 ------------"
|
||||||
|
$LUATOOL -p $DEVICE -f $f -t $f
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "STOOOOP"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Reboot the ESP"
|
||||||
|
$LUATOOL -p $DEVICE -r
|
||||||
|
|
||||||
|
exit 0
|
326
tools/luatool.py
Executable file
326
tools/luatool.py
Executable file
@@ -0,0 +1,326 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# ESP8266 luatool
|
||||||
|
# Author e-mail: 4ref0nt@gmail.com
|
||||||
|
# Site: http://esp8266.ru
|
||||||
|
# Contributions from: https://github.com/sej7278
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
|
||||||
|
# Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import serial
|
||||||
|
from time import sleep
|
||||||
|
import socket
|
||||||
|
import argparse
|
||||||
|
from os.path import basename
|
||||||
|
|
||||||
|
|
||||||
|
version = "0.6.4"
|
||||||
|
|
||||||
|
|
||||||
|
class TransportError(Exception):
|
||||||
|
"""Custom exception to represent errors with a transport
|
||||||
|
"""
|
||||||
|
def __init__(self, message):
|
||||||
|
self.message = message
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractTransport:
|
||||||
|
def __init__(self):
|
||||||
|
raise NotImplementedError('abstract transports cannot be instantiated.')
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
raise NotImplementedError('Function not implemented')
|
||||||
|
|
||||||
|
def read(self, length):
|
||||||
|
raise NotImplementedError('Function not implemented')
|
||||||
|
|
||||||
|
def writeln(self, data, check=1):
|
||||||
|
raise NotImplementedError('Function not implemented')
|
||||||
|
|
||||||
|
def writer(self, data):
|
||||||
|
self.writeln("file.writeline([==[" + data + "]==])\r")
|
||||||
|
|
||||||
|
def performcheck(self, expected):
|
||||||
|
line = ''
|
||||||
|
char = ''
|
||||||
|
i = -1
|
||||||
|
while char != chr(62): # '>'
|
||||||
|
char = self.read(1)
|
||||||
|
if char == '':
|
||||||
|
raise Exception('No proper answer from MCU')
|
||||||
|
if char == chr(13) or char == chr(10): # LF or CR
|
||||||
|
if line != '':
|
||||||
|
line = line.strip()
|
||||||
|
if line+'\r' == expected:
|
||||||
|
sys.stdout.write(" -> ok")
|
||||||
|
else:
|
||||||
|
if line[:4] == "lua:":
|
||||||
|
sys.stdout.write("\r\n\r\nLua ERROR: %s" % line)
|
||||||
|
raise Exception('ERROR from Lua interpreter\r\n\r\n')
|
||||||
|
else:
|
||||||
|
expected = expected.split("\r")[0]
|
||||||
|
sys.stdout.write("\r\n\r\nERROR")
|
||||||
|
sys.stdout.write("\r\n send string : '%s'" % expected)
|
||||||
|
sys.stdout.write("\r\n expected echo : '%s'" % expected)
|
||||||
|
sys.stdout.write("\r\n but got answer : '%s'" % line)
|
||||||
|
sys.stdout.write("\r\n\r\n")
|
||||||
|
raise Exception('Error sending data to MCU\r\n\r\n')
|
||||||
|
line = ''
|
||||||
|
else:
|
||||||
|
line += char
|
||||||
|
if char == chr(62) and expected[i] == char:
|
||||||
|
char = ''
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
|
||||||
|
class SerialTransport(AbstractTransport):
|
||||||
|
def __init__(self, port, baud, delay):
|
||||||
|
self.port = port
|
||||||
|
self.baud = baud
|
||||||
|
self.serial = None
|
||||||
|
self.delay = delay
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.serial = serial.Serial(port, baud)
|
||||||
|
except serial.SerialException as e:
|
||||||
|
raise TransportError(e.strerror)
|
||||||
|
|
||||||
|
self.serial.timeout = 3
|
||||||
|
self.serial.interCharTimeout = 3
|
||||||
|
|
||||||
|
def writeln(self, data, check=1):
|
||||||
|
if self.serial.inWaiting() > 0:
|
||||||
|
self.serial.flushInput()
|
||||||
|
if len(data) > 0:
|
||||||
|
sys.stdout.write("\r\n->")
|
||||||
|
sys.stdout.write(data.split("\r")[0])
|
||||||
|
self.serial.write(data)
|
||||||
|
sleep(self.delay)
|
||||||
|
if check > 0:
|
||||||
|
self.performcheck(data)
|
||||||
|
else:
|
||||||
|
sys.stdout.write(" -> send without check")
|
||||||
|
|
||||||
|
def read(self, length):
|
||||||
|
return self.serial.read(length)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.serial.flush()
|
||||||
|
self.serial.close()
|
||||||
|
|
||||||
|
|
||||||
|
class TcpSocketTransport(AbstractTransport):
|
||||||
|
def __init__(self, host, port):
|
||||||
|
self.host = host
|
||||||
|
self.port = port
|
||||||
|
self.socket = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
except socket.error as e:
|
||||||
|
raise TransportError(e.strerror)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.socket.connect((host, port))
|
||||||
|
except socket.error as e:
|
||||||
|
raise TransportError(e.strerror)
|
||||||
|
# read intro from telnet server (see telnet_srv.lua)
|
||||||
|
self.socket.recv(50)
|
||||||
|
|
||||||
|
def writeln(self, data, check=1):
|
||||||
|
if len(data) > 0:
|
||||||
|
sys.stdout.write("\r\n->")
|
||||||
|
sys.stdout.write(data.split("\r")[0])
|
||||||
|
self.socket.sendall(data)
|
||||||
|
if check > 0:
|
||||||
|
self.performcheck(data)
|
||||||
|
else:
|
||||||
|
sys.stdout.write(" -> send without check")
|
||||||
|
|
||||||
|
def read(self, length):
|
||||||
|
return self.socket.recv(length)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.socket.close()
|
||||||
|
|
||||||
|
|
||||||
|
def decidetransport(cliargs):
|
||||||
|
if cliargs.ip:
|
||||||
|
data = cliargs.ip.split(':')
|
||||||
|
host = data[0]
|
||||||
|
if len(data) == 2:
|
||||||
|
port = int(data[1])
|
||||||
|
else:
|
||||||
|
port = 23
|
||||||
|
return TcpSocketTransport(host, port)
|
||||||
|
else:
|
||||||
|
return SerialTransport(cliargs.port, cliargs.baud, cliargs.delay)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# parse arguments or use defaults
|
||||||
|
parser = argparse.ArgumentParser(description='ESP8266 Lua script uploader.')
|
||||||
|
parser.add_argument('-p', '--port', default='/dev/ttyUSB0', help='Device name, default /dev/ttyUSB0')
|
||||||
|
parser.add_argument('-b', '--baud', default=9600, help='Baudrate, default 9600')
|
||||||
|
parser.add_argument('-f', '--src', default='main.lua', help='Source file on computer, default main.lua')
|
||||||
|
parser.add_argument('-t', '--dest', default=None, help='Destination file on MCU, default to source file name')
|
||||||
|
parser.add_argument('-c', '--compile', action='store_true', help='Compile lua to lc after upload')
|
||||||
|
parser.add_argument('-r', '--restart', action='store_true', help='Restart MCU after upload')
|
||||||
|
parser.add_argument('-d', '--dofile', action='store_true', help='Run the Lua script after upload')
|
||||||
|
parser.add_argument('-v', '--verbose', action='store_true', help="Show progress messages.")
|
||||||
|
parser.add_argument('-a', '--append', action='store_true', help='Append source file to destination file.')
|
||||||
|
parser.add_argument('-l', '--list', action='store_true', help='List files on device')
|
||||||
|
parser.add_argument('-w', '--wipe', action='store_true', help='Delete all lua/lc files on device.')
|
||||||
|
parser.add_argument('-i', '--id', action='store_true', help='Query the modules chip id.')
|
||||||
|
parser.add_argument('-e', '--echo', action='store_true', help='Echo output of MCU until script is terminated.')
|
||||||
|
parser.add_argument('--delay', default=0.3, help='Delay in seconds between each write.', type=float)
|
||||||
|
parser.add_argument('--delete', default=None, help='Delete a lua/lc file from device.')
|
||||||
|
parser.add_argument('--ip', default=None, help='Connect to a telnet server on the device (--ip IP[:port])')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
transport = decidetransport(args)
|
||||||
|
|
||||||
|
if args.list:
|
||||||
|
transport.writeln("local l = file.list();for k,v in pairs(l) do print('name:'..k..', size:'..v)end\r", 0)
|
||||||
|
while True:
|
||||||
|
char = transport.read(1)
|
||||||
|
if char == '' or char == chr(62):
|
||||||
|
break
|
||||||
|
sys.stdout.write(char)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if args.id:
|
||||||
|
transport.writeln("=node.chipid()\r", 0)
|
||||||
|
id=""
|
||||||
|
while True:
|
||||||
|
char = transport.read(1)
|
||||||
|
if char == '' or char == chr(62):
|
||||||
|
break
|
||||||
|
if char.isdigit():
|
||||||
|
id += char
|
||||||
|
print("\n"+id)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if args.wipe:
|
||||||
|
transport.writeln("local l = file.list();for k,v in pairs(l) do print(k)end\r", 0)
|
||||||
|
file_list = []
|
||||||
|
fn = ""
|
||||||
|
while True:
|
||||||
|
char = transport.read(1)
|
||||||
|
if char == '' or char == chr(62):
|
||||||
|
break
|
||||||
|
if char not in ['\r', '\n']:
|
||||||
|
fn += char
|
||||||
|
else:
|
||||||
|
if fn:
|
||||||
|
file_list.append(fn.strip())
|
||||||
|
fn = ''
|
||||||
|
for fn in file_list[1:]: # first line is the list command sent to device
|
||||||
|
if args.verbose:
|
||||||
|
sys.stderr.write("Delete file {} from device.\r\n".format(fn))
|
||||||
|
transport.writeln("file.remove(\"" + fn + "\")\r")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if args.delete:
|
||||||
|
transport.writeln("file.remove(\"" + args.delete + "\")\r")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if args.dest is None:
|
||||||
|
args.dest = basename(args.src)
|
||||||
|
|
||||||
|
# open source file for reading
|
||||||
|
try:
|
||||||
|
f = open(args.src, "rt")
|
||||||
|
except:
|
||||||
|
sys.stderr.write("Could not open input file \"%s\"\n" % args.src)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Verify the selected file will not exceed the size of the serial buffer.
|
||||||
|
# The size of the buffer is 256. This script does not accept files with
|
||||||
|
# lines longer than 230 characters to have some room for command overhead.
|
||||||
|
for ln in f:
|
||||||
|
if len(ln) > 230:
|
||||||
|
sys.stderr.write("File \"%s\" contains a line with more than 240 "
|
||||||
|
"characters. This exceeds the size of the serial buffer.\n"
|
||||||
|
% args.src)
|
||||||
|
f.close()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Go back to the beginning of the file after verifying it has the correct
|
||||||
|
# line length
|
||||||
|
f.seek(0)
|
||||||
|
|
||||||
|
# set serial timeout
|
||||||
|
if args.verbose:
|
||||||
|
sys.stderr.write("Upload starting\r\n")
|
||||||
|
|
||||||
|
# remove existing file on device
|
||||||
|
if args.append==False:
|
||||||
|
if args.verbose:
|
||||||
|
sys.stderr.write("Stage 1. Deleting old file from flash memory")
|
||||||
|
transport.writeln("file.open(\"" + args.dest + "\", \"w\")\r")
|
||||||
|
transport.writeln("file.close()\r")
|
||||||
|
transport.writeln("file.remove(\"" + args.dest + "\")\r")
|
||||||
|
else:
|
||||||
|
if args.verbose:
|
||||||
|
sys.stderr.write("[SKIPPED] Stage 1. Deleting old file from flash memory [SKIPPED]")
|
||||||
|
|
||||||
|
|
||||||
|
# read source file line by line and write to device
|
||||||
|
if args.verbose:
|
||||||
|
sys.stderr.write("\r\nStage 2. Creating file in flash memory and write first line")
|
||||||
|
if args.append:
|
||||||
|
transport.writeln("file.open(\"" + args.dest + "\", \"a+\")\r")
|
||||||
|
else:
|
||||||
|
transport.writeln("file.open(\"" + args.dest + "\", \"w+\")\r")
|
||||||
|
line = f.readline()
|
||||||
|
if args.verbose:
|
||||||
|
sys.stderr.write("\r\nStage 3. Start writing data to flash memory...")
|
||||||
|
while line != '':
|
||||||
|
transport.writer(line.strip())
|
||||||
|
line = f.readline()
|
||||||
|
|
||||||
|
# close both files
|
||||||
|
f.close()
|
||||||
|
if args.verbose:
|
||||||
|
sys.stderr.write("\r\nStage 4. Flush data and closing file")
|
||||||
|
transport.writeln("file.flush()\r")
|
||||||
|
transport.writeln("file.close()\r")
|
||||||
|
|
||||||
|
# compile?
|
||||||
|
if args.compile:
|
||||||
|
if args.verbose:
|
||||||
|
sys.stderr.write("\r\nStage 5. Compiling")
|
||||||
|
transport.writeln("node.compile(\"" + args.dest + "\")\r")
|
||||||
|
transport.writeln("file.remove(\"" + args.dest + "\")\r")
|
||||||
|
|
||||||
|
# restart or dofile
|
||||||
|
if args.restart:
|
||||||
|
transport.writeln("node.restart()\r")
|
||||||
|
if args.dofile: # never exec if restart=1
|
||||||
|
transport.writeln("dofile(\"" + args.dest + "\")\r", 0)
|
||||||
|
|
||||||
|
if args.echo:
|
||||||
|
if args.verbose:
|
||||||
|
sys.stderr.write("\r\nEchoing MCU output, press Ctrl-C to exit")
|
||||||
|
while True:
|
||||||
|
sys.stdout.write(transport.read(1))
|
||||||
|
|
||||||
|
# close serial port
|
||||||
|
transport.close()
|
||||||
|
|
||||||
|
# flush screen
|
||||||
|
sys.stdout.flush()
|
||||||
|
sys.stderr.flush()
|
||||||
|
sys.stderr.write("\r\n--->>> All done <<<---\r\n")
|
0
programESP.sh → tools/programESP.sh
Normal file → Executable file
0
programESP.sh → tools/programESP.sh
Normal file → Executable file
@@ -1,6 +1,7 @@
|
|||||||
-- Example usage of the word clock
|
-- Example usage of the word clock
|
||||||
dofile("../wordclock.lua")
|
dofile("../wordclock.lua")
|
||||||
|
|
||||||
|
print "------- Manual test ----"
|
||||||
-- Manually set something
|
-- Manually set something
|
||||||
leds=display_timestat(15,30)
|
leds=display_timestat(15,30)
|
||||||
for k,v in pairs(leds) do
|
for k,v in pairs(leds) do
|
||||||
@@ -8,6 +9,7 @@ for k,v in pairs(leds) do
|
|||||||
print(k)
|
print(k)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
print "---------------------"
|
||||||
|
|
||||||
function checkWords(leds, expected, hour, min)
|
function checkWords(leds, expected, hour, min)
|
||||||
for k, v in pairs(leds) do
|
for k, v in pairs(leds) do
|
||||||
@@ -34,6 +36,19 @@ function checkWords(leds, expected, hour, min)
|
|||||||
print(hour .. ":" .. min)
|
print(hour .. ":" .. min)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function checkCharacter(words, expected)
|
||||||
|
if (words == nil or expected == nil) then
|
||||||
|
print("Not all parameter set to checkCharacter")
|
||||||
|
os.exit(1)
|
||||||
|
end
|
||||||
|
if (words ~= expected) then
|
||||||
|
print("Not all character found. Expected " .. expected .. ", but found " .. words)
|
||||||
|
os.exit(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
print ""
|
||||||
|
print "----------- Unit tests -------------"
|
||||||
-- Unit tests
|
-- Unit tests
|
||||||
leds=display_timestat(1,0)
|
leds=display_timestat(1,0)
|
||||||
expected={}
|
expected={}
|
||||||
@@ -41,6 +56,7 @@ expected.itis=1
|
|||||||
expected.one=1
|
expected.one=1
|
||||||
expected.clock=1
|
expected.clock=1
|
||||||
checkWords(leds, expected, 1, 0)
|
checkWords(leds, expected, 1, 0)
|
||||||
|
checkCharacter(display_countwords_de(leds), 11)
|
||||||
|
|
||||||
leds=display_timestat(2,5)
|
leds=display_timestat(2,5)
|
||||||
expected={}
|
expected={}
|
||||||
@@ -48,6 +64,7 @@ expected.two=1
|
|||||||
expected.fiveMin=1
|
expected.fiveMin=1
|
||||||
expected.after=1
|
expected.after=1
|
||||||
checkWords(leds, expected, 2 , 5)
|
checkWords(leds, expected, 2 , 5)
|
||||||
|
checkCharacter(display_countwords_de(leds), 12)
|
||||||
|
|
||||||
leds=display_timestat(3,10)
|
leds=display_timestat(3,10)
|
||||||
expected={}
|
expected={}
|
||||||
@@ -55,6 +72,7 @@ expected.three=1
|
|||||||
expected.tenMin=1
|
expected.tenMin=1
|
||||||
expected.after=1
|
expected.after=1
|
||||||
checkWords(leds, expected, 3 , 10)
|
checkWords(leds, expected, 3 , 10)
|
||||||
|
checkCharacter(display_countwords_de(leds), 12)
|
||||||
|
|
||||||
leds=display_timestat(4,15)
|
leds=display_timestat(4,15)
|
||||||
expected={}
|
expected={}
|
||||||
@@ -62,14 +80,15 @@ expected.four=1
|
|||||||
expected.after=1
|
expected.after=1
|
||||||
expected.quater=1
|
expected.quater=1
|
||||||
checkWords(leds, expected, 4 , 15)
|
checkWords(leds, expected, 4 , 15)
|
||||||
|
checkCharacter(display_countwords_de(leds), 15)
|
||||||
|
|
||||||
leds=display_timestat(5,20)
|
leds=display_timestat(5,20)
|
||||||
expected={}
|
expected={}
|
||||||
expected.six=1
|
expected.five=1
|
||||||
expected.tenMin=1
|
expected.twenty=1
|
||||||
expected.before=1
|
expected.after=1
|
||||||
expected.half=1
|
|
||||||
checkWords(leds, expected, 5 , 20)
|
checkWords(leds, expected, 5 , 20)
|
||||||
|
checkCharacter(display_countwords_de(leds), 15)
|
||||||
|
|
||||||
leds=display_timestat(6,25)
|
leds=display_timestat(6,25)
|
||||||
expected={}
|
expected={}
|
||||||
@@ -78,6 +97,7 @@ expected.fiveMin=1
|
|||||||
expected.before=1
|
expected.before=1
|
||||||
expected.half=1
|
expected.half=1
|
||||||
checkWords(leds, expected, 6 , 25)
|
checkWords(leds, expected, 6 , 25)
|
||||||
|
checkCharacter(display_countwords_de(leds), 17)
|
||||||
|
|
||||||
leds=display_timestat(7,30)
|
leds=display_timestat(7,30)
|
||||||
expected={}
|
expected={}
|
||||||
@@ -85,6 +105,7 @@ expected.itis=1
|
|||||||
expected.eight=1
|
expected.eight=1
|
||||||
expected.half=1
|
expected.half=1
|
||||||
checkWords(leds, expected, 7 , 30)
|
checkWords(leds, expected, 7 , 30)
|
||||||
|
checkCharacter(display_countwords_de(leds), 13)
|
||||||
|
|
||||||
leds=display_timestat(8,35)
|
leds=display_timestat(8,35)
|
||||||
expected={}
|
expected={}
|
||||||
@@ -93,14 +114,15 @@ expected.half=1
|
|||||||
expected.fiveMin=1
|
expected.fiveMin=1
|
||||||
expected.after=1
|
expected.after=1
|
||||||
checkWords(leds, expected, 8 , 35)
|
checkWords(leds, expected, 8 , 35)
|
||||||
|
checkCharacter(display_countwords_de(leds), 16)
|
||||||
|
|
||||||
leds=display_timestat(9,40)
|
leds=display_timestat(9,40)
|
||||||
expected={}
|
expected={}
|
||||||
expected.ten=1
|
expected.ten=1
|
||||||
expected.half=1
|
expected.twenty=1
|
||||||
expected.tenMin=1
|
expected.before=1
|
||||||
expected.after=1
|
|
||||||
checkWords(leds, expected, 9 , 40)
|
checkWords(leds, expected, 9 , 40)
|
||||||
|
checkCharacter(display_countwords_de(leds), 14)
|
||||||
|
|
||||||
leds=display_timestat(10,45)
|
leds=display_timestat(10,45)
|
||||||
expected={}
|
expected={}
|
||||||
@@ -108,6 +130,7 @@ expected.eleven=1
|
|||||||
expected.quater=1
|
expected.quater=1
|
||||||
expected.before=1
|
expected.before=1
|
||||||
checkWords(leds, expected, 10 , 45)
|
checkWords(leds, expected, 10 , 45)
|
||||||
|
checkCharacter(display_countwords_de(leds), 13)
|
||||||
|
|
||||||
leds=display_timestat(11,50)
|
leds=display_timestat(11,50)
|
||||||
expected={}
|
expected={}
|
||||||
@@ -115,13 +138,15 @@ expected.twelve=1
|
|||||||
expected.tenMin=1
|
expected.tenMin=1
|
||||||
expected.before=1
|
expected.before=1
|
||||||
checkWords(leds, expected, 11 , 50)
|
checkWords(leds, expected, 11 , 50)
|
||||||
|
checkCharacter(display_countwords_de(leds), 12)
|
||||||
|
|
||||||
leds=display_timestat(12,55)
|
leds=display_timestat(12,55)
|
||||||
expected={}
|
expected={}
|
||||||
expected.one=1
|
expected.oneLong=1
|
||||||
expected.fiveMin=1
|
expected.fiveMin=1
|
||||||
expected.before=1
|
expected.before=1
|
||||||
checkWords(leds, expected, 12 , 55)
|
checkWords(leds, expected, 12 , 55)
|
||||||
|
checkCharacter(display_countwords_de(leds), 11)
|
||||||
|
|
||||||
leds=display_timestat(13,00)
|
leds=display_timestat(13,00)
|
||||||
expected={}
|
expected={}
|
||||||
@@ -129,6 +154,7 @@ expected.itis=1
|
|||||||
expected.one=1
|
expected.one=1
|
||||||
expected.clock=1
|
expected.clock=1
|
||||||
checkWords(leds, expected, 13 , 00)
|
checkWords(leds, expected, 13 , 00)
|
||||||
|
checkCharacter(display_countwords_de(leds), 11)
|
||||||
|
|
||||||
-- test the minutes inbetween
|
-- test the minutes inbetween
|
||||||
leds=display_timestat(14,01)
|
leds=display_timestat(14,01)
|
||||||
@@ -138,6 +164,7 @@ expected.two=1
|
|||||||
expected.min1=1
|
expected.min1=1
|
||||||
expected.clock=1
|
expected.clock=1
|
||||||
checkWords(leds, expected, 14 , 01)
|
checkWords(leds, expected, 14 , 01)
|
||||||
|
checkCharacter(display_countwords_de(leds), 12)
|
||||||
|
|
||||||
leds=display_timestat(15,02)
|
leds=display_timestat(15,02)
|
||||||
expected={}
|
expected={}
|
||||||
@@ -146,6 +173,7 @@ expected.three=1
|
|||||||
expected.min2=1
|
expected.min2=1
|
||||||
expected.clock=1
|
expected.clock=1
|
||||||
checkWords(leds, expected, 15 , 02)
|
checkWords(leds, expected, 15 , 02)
|
||||||
|
checkCharacter(display_countwords_de(leds), 12)
|
||||||
|
|
||||||
leds=display_timestat(16,03)
|
leds=display_timestat(16,03)
|
||||||
expected={}
|
expected={}
|
||||||
@@ -154,6 +182,7 @@ expected.four=1
|
|||||||
expected.min3=1
|
expected.min3=1
|
||||||
expected.clock=1
|
expected.clock=1
|
||||||
checkWords(leds, expected, 16 , 03)
|
checkWords(leds, expected, 16 , 03)
|
||||||
|
checkCharacter(display_countwords_de(leds), 12)
|
||||||
|
|
||||||
leds=display_timestat(17,04)
|
leds=display_timestat(17,04)
|
||||||
expected={}
|
expected={}
|
||||||
@@ -162,6 +191,7 @@ expected.five=1
|
|||||||
expected.min4=1
|
expected.min4=1
|
||||||
expected.clock=1
|
expected.clock=1
|
||||||
checkWords(leds, expected, 17 , 04)
|
checkWords(leds, expected, 17 , 04)
|
||||||
|
checkCharacter(display_countwords_de(leds), 12)
|
||||||
|
|
||||||
leds=display_timestat(18,06)
|
leds=display_timestat(18,06)
|
||||||
expected={}
|
expected={}
|
||||||
@@ -170,6 +200,7 @@ expected.after=1
|
|||||||
expected.min1=1
|
expected.min1=1
|
||||||
expected.six=1
|
expected.six=1
|
||||||
checkWords(leds, expected, 18 , 06)
|
checkWords(leds, expected, 18 , 06)
|
||||||
|
checkCharacter(display_countwords_de(leds), 13)
|
||||||
|
|
||||||
leds=display_timestat(19,09)
|
leds=display_timestat(19,09)
|
||||||
expected={}
|
expected={}
|
||||||
@@ -178,6 +209,7 @@ expected.after=1
|
|||||||
expected.min4=1
|
expected.min4=1
|
||||||
expected.seven=1
|
expected.seven=1
|
||||||
checkWords(leds, expected, 19 , 09)
|
checkWords(leds, expected, 19 , 09)
|
||||||
|
checkCharacter(display_countwords_de(leds), 14)
|
||||||
|
|
||||||
leds=display_timestat(20,17)
|
leds=display_timestat(20,17)
|
||||||
expected={}
|
expected={}
|
||||||
@@ -186,6 +218,7 @@ expected.after=1
|
|||||||
expected.min2=1
|
expected.min2=1
|
||||||
expected.eight=1
|
expected.eight=1
|
||||||
checkWords(leds, expected, 20 , 17)
|
checkWords(leds, expected, 20 , 17)
|
||||||
|
checkCharacter(display_countwords_de(leds), 15)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
64
webpage.html
Normal file
64
webpage.html
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html><head><title>WordClock Setup Page</title>
|
||||||
|
<style type="text/css">
|
||||||
|
#table-6 {
|
||||||
|
width: 100%
|
||||||
|
border: 1px solid #B0B0B0;
|
||||||
|
}
|
||||||
|
#table-6 tbody {
|
||||||
|
/* Kind of irrelevant unless your .css is alreadt doing something else */
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
outline: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
vertical-align: baseline;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
#table-6 thead {
|
||||||
|
text-align: left;<tr><th>Three quater</th><td><input type="checkbox" name="threequater" ></td><td>Dreiviertel Joa/nei</td></tr>
|
||||||
|
|
||||||
|
}
|
||||||
|
#table-6 thead th {
|
||||||
|
background: -moz-linear-gradient(top, #F0F0F0 0, #DBDBDB 100%);
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #F0F0F0), color-stop(100%, #DBDBDB));
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F0F0F0', endColorstr='#DBDBDB', GradientType=0);
|
||||||
|
border: 1px solid #B0B0B0;
|
||||||
|
color: #444;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 3px 10px;
|
||||||
|
}
|
||||||
|
#table-6 td {
|
||||||
|
padding: 3px 10px;
|
||||||
|
|
||||||
|
}
|
||||||
|
#table-6 tr:nth-child(even) {
|
||||||
|
background: #F2F2F2;
|
||||||
|
}
|
||||||
|
</style></head>
|
||||||
|
<body>
|
||||||
|
<h1>Welcome to the WordClock</h1>
|
||||||
|
<h2>Initial Setup</h2>
|
||||||
|
Please note that all settings are mandatory<br /><br />
|
||||||
|
<form action="/" method="POST">
|
||||||
|
<table id="table-6">
|
||||||
|
<tr><th><b>WIFI-SSID</b></th><td><input id="ssid" name="ssid" value="$SSID"></td><td>SSID of the wireless network</td></tr>
|
||||||
|
<tr><th>WIFI-Password</th><td><input id="password" name="password"></td><td>Password of the wireless network</td></tr>
|
||||||
|
<tr><th>SNTP Server</th><td><input id="sntpserver" name="sntpserver" value="$SNTPSERVER"></td><td>Server to sync the time with. Only one ntp server is allowed.</tr>
|
||||||
|
<tr><th>Offset to UTC time</th><td><input id="timezoneoffset" name="timezoneoffset" value="$TIMEOFFSET"></td><td>Define the offset to UTC time in hours. For example +1 hour for Germany</tr>
|
||||||
|
<tr><th>Foreground Color</th><td><input type="color" name="fcolor" value="$HEXCOLORFG"></td><td>LED Color for all minutes, divisible by five</td></tr>
|
||||||
|
<tr><th>Background Color</th><td><input type="color" name="bcolor" value="$HEXCOLORBG"></td><td>Background LED Color</td></tr>
|
||||||
|
<tr><th>1. Minute Color</th><td><input type="color" name="colorMin1" value="$HEXCOLOR1"></td><td>First minute after</td></tr>
|
||||||
|
<tr><th>2. Minute Color</th><td><input type="color" name="colorMin2" value="$HEXCOLOR2"></td><td>Second minute after</td></tr>
|
||||||
|
<tr><th>3. Minute Color</th><td><input type="color" name="colorMin3" value="$HEXCOLOR3"></td><td>Third minute after</td></tr>
|
||||||
|
<tr><th>4. Minute Color</th><td><input type="color" name="colorMin4" value="$HEXCOLOR4"></td><td>Fourth minute after</td></tr>
|
||||||
|
|
||||||
|
<tr><th>Three quater</th><td><input type="checkbox" name="threequater" $THREEQUATER></td><td>Dreiviertel Joa/nei</td></tr>
|
||||||
|
<tr><td colspan="3"><div align="center"><input type="submit" value="Save Configuration" onclick="this.value='Submitting ..';this.disabled='disabled'; this.form.submit();"></div></td></tr>
|
||||||
|
<tr><td colspan="3"><div align="center"><input type="submit" name="action" value="Reboot"></div></td></tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
$ADDITIONAL_LINE
|
||||||
|
</body>
|
||||||
|
</html>
|
295
webserver.lua
Normal file
295
webserver.lua
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
--TODO:
|
||||||
|
|
||||||
|
configFile="config.lua"
|
||||||
|
|
||||||
|
sentBytes=0
|
||||||
|
function sendPage(conn, nameOfFile, replaceMap)
|
||||||
|
collectgarbage()
|
||||||
|
print("Sending " .. nameOfFile .. " " .. sentBytes .. "B already; " .. node.heap() .. "B in heap")
|
||||||
|
conn:on("sent", function(conn)
|
||||||
|
if (sentBytes == 0) then
|
||||||
|
conn:close()
|
||||||
|
print("Page sent")
|
||||||
|
collectgarbage()
|
||||||
|
else
|
||||||
|
print("Next")
|
||||||
|
sendPage(conn, nameOfFile, replaceMap)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
if file.open(nameOfFile, "r") then
|
||||||
|
local buf=""
|
||||||
|
if (sentBytes <= 0) then
|
||||||
|
buf=buf .. "HTTP/1.1 200 OK\r\n"
|
||||||
|
buf=buf .. "Content-Type: text/html\r\n"
|
||||||
|
buf=buf .. "Connection: close\r\n"
|
||||||
|
buf=buf .. "Date: Thu, 29 Dec 2016 20:18:20 GMT\r\n"
|
||||||
|
buf=buf .. "\r\n\r\n"
|
||||||
|
end
|
||||||
|
-- amount of sent bytes is always zero at the beginning (so no problem)
|
||||||
|
file.seek("set", sentBytes)
|
||||||
|
|
||||||
|
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
|
||||||
|
if (replaceMap ~= nil) then
|
||||||
|
for key,value in pairs(replaceMap)
|
||||||
|
do
|
||||||
|
line = string.gsub(line, key, value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
buf = buf .. line
|
||||||
|
|
||||||
|
-- Sent after 1k data
|
||||||
|
if (string.len(buf) >= 700) then
|
||||||
|
line=nil
|
||||||
|
conn:send(buf)
|
||||||
|
print("Sent part of " .. sentBytes .. "B")
|
||||||
|
-- end the function, this part is sent
|
||||||
|
return
|
||||||
|
else
|
||||||
|
-- fetch the next line
|
||||||
|
line = file.readline()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--reset amount of sent bytes, as we reached the end
|
||||||
|
sentBytes=0
|
||||||
|
-- send the rest
|
||||||
|
conn:send(buf)
|
||||||
|
print("Sent rest")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function fillDynamicMap()
|
||||||
|
replaceMap = {}
|
||||||
|
ssid, _ = wifi.sta.getconfig()
|
||||||
|
|
||||||
|
if (ssid == nil) then
|
||||||
|
ssid="Not set"
|
||||||
|
end
|
||||||
|
if (sntpserverhostname == nil) then
|
||||||
|
sntpserverhostname="ptbtime1.ptb.de"
|
||||||
|
end
|
||||||
|
if (timezoneoffset == nil) then
|
||||||
|
timezoneoffset=1
|
||||||
|
end
|
||||||
|
-- Set the default color, if nothing is set
|
||||||
|
if (color == nil) then
|
||||||
|
color=string.char(0,0,250)
|
||||||
|
end
|
||||||
|
if (color1 == nil) then
|
||||||
|
color1=color
|
||||||
|
end
|
||||||
|
if (color2 == nil) then
|
||||||
|
color2=color
|
||||||
|
end
|
||||||
|
if (color3 == nil) then
|
||||||
|
color3=color
|
||||||
|
end
|
||||||
|
if (color4 == nil) then
|
||||||
|
color4=color
|
||||||
|
end
|
||||||
|
if (colorBg == nil) then
|
||||||
|
colorBg=string.char(0,0,0) -- black is the default background color
|
||||||
|
end
|
||||||
|
local hexColor = "#" .. string.format("%02x",string.byte(color,2)) .. string.format("%02x",string.byte(color,1)) .. string.format("%02x",string.byte(color,3))
|
||||||
|
local hexColor1 = "#" .. string.format("%02x",string.byte(color1,2)) .. string.format("%02x",string.byte(color1,1)) .. string.format("%02x",string.byte(color1,3))
|
||||||
|
local hexColor2 = "#" .. string.format("%02x",string.byte(color2,2)) .. string.format("%02x",string.byte(color2,1)) .. string.format("%02x",string.byte(color2,3))
|
||||||
|
local hexColor3 = "#" .. string.format("%02x",string.byte(color3,2)) .. string.format("%02x",string.byte(color3,1)) .. string.format("%02x",string.byte(color3,3))
|
||||||
|
local hexColor4 = "#" .. string.format("%02x",string.byte(color4,2)) .. string.format("%02x",string.byte(color4,1)) .. string.format("%02x",string.byte(color4,3))
|
||||||
|
local hexColorBg = "#" .. string.format("%02x",string.byte(colorBg,2)) .. string.format("%02x",string.byte(colorBg,1)) .. string.format("%02x",string.byte(colorBg,3))
|
||||||
|
|
||||||
|
replaceMap["$SSID"]=ssid
|
||||||
|
replaceMap["$SNTPSERVER"]=sntpserverhostname
|
||||||
|
replaceMap["$TIMEOFFSET"]=timezoneoffset
|
||||||
|
replaceMap["$THREEQUATER"]=(threequater and "checked" or "")
|
||||||
|
replaceMap["$ADDITIONAL_LINE"]=""
|
||||||
|
replaceMap["$HEXCOLORFG"]=hexColor
|
||||||
|
replaceMap["$HEXCOLOR1"]=hexColor1
|
||||||
|
replaceMap["$HEXCOLOR2"]=hexColor2
|
||||||
|
replaceMap["$HEXCOLOR3"]=hexColor3
|
||||||
|
replaceMap["$HEXCOLOR4"]=hexColor4
|
||||||
|
replaceMap["$HEXCOLORBG"]=hexColorBg
|
||||||
|
return replaceMap
|
||||||
|
end
|
||||||
|
|
||||||
|
function startWebServer()
|
||||||
|
srv=net.createServer(net.TCP)
|
||||||
|
srv:listen(80,function(conn)
|
||||||
|
conn:on("receive", function(conn,payload)
|
||||||
|
|
||||||
|
if (payload:find("GET /") ~= nil) then
|
||||||
|
--here is code for handling http request from a web-browser
|
||||||
|
|
||||||
|
if (sendPage ~= nil) then
|
||||||
|
print("Sending webpage.html ...")
|
||||||
|
-- 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")
|
||||||
|
--Next lines catches POST-requests without POST-data....
|
||||||
|
if postdatastart==nil then postdatastart = 1 end
|
||||||
|
local postRequestData=string.sub(payload,postdatastart+1)
|
||||||
|
local _POST = {}
|
||||||
|
for i, j in string.gmatch(postRequestData, "(%w+)=([^&]+)&*") do
|
||||||
|
_POST[i] = j
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Do the magic!
|
||||||
|
if (_POST.action ~= nil and _POST.action == "Reboot") then
|
||||||
|
node.restart()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if ((_POST.ssid~=nil) and (_POST.sntpserver~=nil) and (_POST.timezoneoffset~=nil)) then
|
||||||
|
print("New config!")
|
||||||
|
if (_POST.password==nil) then
|
||||||
|
_, password, _, _ = wifi.sta.getconfig()
|
||||||
|
print("Restoring password : " .. password)
|
||||||
|
_POST.password = password
|
||||||
|
password = nil
|
||||||
|
end
|
||||||
|
-- Safe configuration:
|
||||||
|
file.remove(configFile .. ".new")
|
||||||
|
sec, _ = rtctime.get()
|
||||||
|
file.open(configFile.. ".new", "w+")
|
||||||
|
file.write("-- Config\n" .. "wifi.sta.config(\"" .. _POST.ssid .. "\",[[" .. _POST.password .. "]])\n" .. "sntpserverhostname=\"" .. _POST.sntpserver .. "\"\n" .. "timezoneoffset=\"" .. _POST.timezoneoffset .. "\"\n")
|
||||||
|
if ( _POST.fcolor ~= nil) then
|
||||||
|
-- color=string.char(_POST.green, _POST.red, _POST.blue)
|
||||||
|
print ("Got fcolor: " .. _POST.fcolor)
|
||||||
|
local hexColor=string.sub(_POST.fcolor, 4)
|
||||||
|
local red = tonumber(string.sub(hexColor, 1, 2), 16)
|
||||||
|
local green = tonumber(string.sub(hexColor, 3, 4), 16)
|
||||||
|
local blue = tonumber(string.sub(hexColor, 5, 6), 16)
|
||||||
|
file.write("color=string.char(" .. green .. "," .. red .. "," .. blue .. ")\n")
|
||||||
|
-- fill the current values
|
||||||
|
color=string.char(green, red, blue)
|
||||||
|
end
|
||||||
|
if ( _POST.colorMin1 ~= nil) then
|
||||||
|
local hexColor=string.sub(_POST.colorMin1, 4)
|
||||||
|
local red = tonumber(string.sub(hexColor, 1, 2), 16)
|
||||||
|
local green = tonumber(string.sub(hexColor, 3, 4), 16)
|
||||||
|
local blue = tonumber(string.sub(hexColor, 5, 6), 16)
|
||||||
|
file.write("color1=string.char(" .. green .. "," .. red .. "," .. blue .. ")\n")
|
||||||
|
-- fill the current values
|
||||||
|
color1=string.char(green, red, blue)
|
||||||
|
end
|
||||||
|
if ( _POST.colorMin2 ~= nil) then
|
||||||
|
local hexColor=string.sub(_POST.colorMin2, 4)
|
||||||
|
local red = tonumber(string.sub(hexColor, 1, 2), 16)
|
||||||
|
local green = tonumber(string.sub(hexColor, 3, 4), 16)
|
||||||
|
local blue = tonumber(string.sub(hexColor, 5, 6), 16)
|
||||||
|
file.write("color2=string.char(" .. green .. "," .. red .. "," .. blue .. ")\n")
|
||||||
|
-- fill the current values
|
||||||
|
color2=string.char(green, red, blue)
|
||||||
|
end
|
||||||
|
if ( _POST.colorMin3 ~= nil) then
|
||||||
|
local hexColor=string.sub(_POST.colorMin3, 4)
|
||||||
|
local red = tonumber(string.sub(hexColor, 1, 2), 16)
|
||||||
|
local green = tonumber(string.sub(hexColor, 3, 4), 16)
|
||||||
|
local blue = tonumber(string.sub(hexColor, 5, 6), 16)
|
||||||
|
file.write("color3=string.char(" .. green .. "," .. red .. "," .. blue .. ")\n")
|
||||||
|
-- fill the current values
|
||||||
|
color3=string.char(green, red, blue)
|
||||||
|
end
|
||||||
|
if ( _POST.colorMin4 ~= nil) then
|
||||||
|
local hexColor=string.sub(_POST.colorMin4, 4)
|
||||||
|
local red = tonumber(string.sub(hexColor, 1, 2), 16)
|
||||||
|
local green = tonumber(string.sub(hexColor, 3, 4), 16)
|
||||||
|
local blue = tonumber(string.sub(hexColor, 5, 6), 16)
|
||||||
|
file.write("color4=string.char(" .. green .. "," .. red .. "," .. blue .. ")\n")
|
||||||
|
-- fill the current values
|
||||||
|
color4=string.char(green, red, blue)
|
||||||
|
end
|
||||||
|
if ( _POST.bcolor ~= nil) then
|
||||||
|
local hexColor=string.sub(_POST.bcolor, 4)
|
||||||
|
local red = tonumber(string.sub(hexColor, 1, 2), 16)
|
||||||
|
local green = tonumber(string.sub(hexColor, 3, 4), 16)
|
||||||
|
local blue = tonumber(string.sub(hexColor, 5, 6), 16)
|
||||||
|
file.write("colorBg=string.char(" .. green .. "," .. red .. "," .. blue .. ")\n")
|
||||||
|
-- fill the current values
|
||||||
|
colorBg=string.char(green, red, blue)
|
||||||
|
end
|
||||||
|
if (getTime ~= nil) then
|
||||||
|
time = getTime(sec, timezoneoffset)
|
||||||
|
file.write("print(\"Config from " .. time.year .. "-" .. time.month .. "-" .. time.day .. " " .. time.hour .. ":" .. time.minute .. ":" .. time.second .. "\")\n")
|
||||||
|
end
|
||||||
|
if (_POST.threequater ~= nil) then
|
||||||
|
file.write("threequater=true\n")
|
||||||
|
-- fill the current values
|
||||||
|
threequater=true
|
||||||
|
else
|
||||||
|
file.write("threequater=nil\n") -- unset threequater
|
||||||
|
-- fill the current values
|
||||||
|
threequater=nil
|
||||||
|
end
|
||||||
|
file.close()
|
||||||
|
collectgarbage()
|
||||||
|
sec=nil
|
||||||
|
file.remove(configFile)
|
||||||
|
print("Rename config")
|
||||||
|
if (file.rename(configFile .. ".new", configFile)) then
|
||||||
|
print("Successfully")
|
||||||
|
tmr.alarm(3, 20, 0 ,function()
|
||||||
|
replaceMap=fillDynamicMap()
|
||||||
|
replaceMap["$ADDITIONAL_LINE"]="<h2><font color=\"green\">New configuration saved</font></h2>"
|
||||||
|
print("Send success to client")
|
||||||
|
sendPage(conn, "webpage.html", replaceMap)
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
tmr.alarm(3, 20, 0 ,function()
|
||||||
|
replaceMap=fillDynamicMap()
|
||||||
|
replaceMap["$ADDITIONAL_LINE"]="<h2><font color=\"red\">ERROR</font></h2>"
|
||||||
|
sendPage(conn, "webpage.html", replaceMap)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
replaceMap=fillDynamicMap()
|
||||||
|
replaceMap["$ADDITIONAL_LINE"]="<h2><font color=\"orange\">Not all parameters set</font></h2>"
|
||||||
|
sendPage(conn, "webpage.html", replaceMap)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
print("Hello via telnet")
|
||||||
|
--here is code, if the connection is not from a webbrowser, i.e. telnet or nc
|
||||||
|
global_c=conn
|
||||||
|
function s_output(str)
|
||||||
|
if(global_c~=nil)
|
||||||
|
then global_c:send(str)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
node.output(s_output, 0)
|
||||||
|
global_c:on("receive",function(c,l)
|
||||||
|
node.input(l)
|
||||||
|
end)
|
||||||
|
global_c:on("disconnection",function(c)
|
||||||
|
node.output(nil)
|
||||||
|
global_c=nil
|
||||||
|
end)
|
||||||
|
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
|
||||||
|
|
||||||
|
--reset amount of sent bytes, as we reached the end
|
||||||
|
sentBytes=0
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
end
|
@@ -1,3 +0,0 @@
|
|||||||
-- Tell the chip to connect to thi access point
|
|
||||||
wifi.setmode(wifi.STATION)
|
|
||||||
wifi.sta.config("SSID","password")
|
|
122
wordclock.lua
122
wordclock.lua
@@ -1,16 +1,20 @@
|
|||||||
-- Revese engeeniered code of display_wc_ger.c by Vlad Tepesch
|
-- Revese engeeniered code of display_wc_ger.c by Vlad Tepesch
|
||||||
-- See https://www.mikrocontroller.net/articles/Word_Clock_Variante_1#Download
|
-- See https://www.mikrocontroller.net/articles/Word_Clock_Variante_1#Download
|
||||||
|
|
||||||
-- Return the leds to use
|
-- @fn display_timestat
|
||||||
-- the granuality is 5 minutes
|
-- Return the leds to use the granuality is 5 minutes
|
||||||
|
-- @param hours the current hours (0-23)
|
||||||
|
-- @param minutes the current minute (0-59)
|
||||||
|
-- @param longmode (optional parameter) 0: no long mode, 1: long mode (itis will be set)
|
||||||
function display_timestat(hours, minutes, longmode)
|
function display_timestat(hours, minutes, longmode)
|
||||||
if (longmode == nil) then
|
if (longmode == nil) then
|
||||||
longmode=0
|
longmode=0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- generate an empty return type
|
-- generate an empty return type
|
||||||
local ret = { itis=0, fiveMin=0, tenMin=0, after=0, before=0, threeHour=0, quater=0, half=0, s=0,
|
local ret = { itis=0, fiveMin=0, tenMin=0, after=0, before=0, threeHour=0, quater=0, threequater=0, half=0, s=0,
|
||||||
one=0, two=0, three=0, four=0, five=0, six=0, seven=0, eight=0, nine=0, ten=0, eleven=0, twelve=0,
|
one=0, oneLong=0, two=0, three=0, four=0, five=0, six=0, seven=0, eight=0, nine=0, ten=0, eleven=0, twelve=0,
|
||||||
|
twenty=0,
|
||||||
clock=0, sr_nc=0, min1=0, min2=0, min3=0, min4=0 }
|
clock=0, sr_nc=0, min1=0, min2=0, min3=0, min4=0 }
|
||||||
|
|
||||||
-- return black screen if there is no real time given
|
-- return black screen if there is no real time given
|
||||||
@@ -20,7 +24,7 @@ function display_timestat(hours, minutes, longmode)
|
|||||||
|
|
||||||
-- transcode minutes
|
-- transcode minutes
|
||||||
local minutesLeds = minutes%5
|
local minutesLeds = minutes%5
|
||||||
minutes=math.floor(minutes/5)
|
local minutes=math.floor(minutes/5)
|
||||||
|
|
||||||
-- "It is" only display each half hour and each hour
|
-- "It is" only display each half hour and each hour
|
||||||
-- or if longmode is set
|
-- or if longmode is set
|
||||||
@@ -42,9 +46,8 @@ function display_timestat(hours, minutes, longmode)
|
|||||||
ret.quater=1
|
ret.quater=1
|
||||||
ret.after=1
|
ret.after=1
|
||||||
elseif (minutes==4) then
|
elseif (minutes==4) then
|
||||||
ret.tenMin=1
|
ret.twenty=1
|
||||||
ret.half=1
|
ret.after=1
|
||||||
ret.before=1
|
|
||||||
elseif (minutes==5) then
|
elseif (minutes==5) then
|
||||||
ret.fiveMin=1
|
ret.fiveMin=1
|
||||||
ret.half=1
|
ret.half=1
|
||||||
@@ -56,12 +59,16 @@ function display_timestat(hours, minutes, longmode)
|
|||||||
ret.half=1
|
ret.half=1
|
||||||
ret.after=1
|
ret.after=1
|
||||||
elseif (minutes==8) then
|
elseif (minutes==8) then
|
||||||
ret.tenMin=1
|
ret.twenty=1
|
||||||
ret.half=1
|
|
||||||
ret.after=1
|
|
||||||
elseif (minutes==9) then
|
|
||||||
ret.quater=1
|
|
||||||
ret.before=1
|
ret.before=1
|
||||||
|
elseif (minutes==9) then
|
||||||
|
-- Hande if three quater or quater before is displayed
|
||||||
|
if (threequater ~= nil) then
|
||||||
|
ret.threequater=1
|
||||||
|
else
|
||||||
|
ret.quater = 1
|
||||||
|
ret.before = 1
|
||||||
|
end
|
||||||
elseif (minutes==10) then
|
elseif (minutes==10) then
|
||||||
ret.tenMin=1
|
ret.tenMin=1
|
||||||
ret.before=1
|
ret.before=1
|
||||||
@@ -70,7 +77,7 @@ function display_timestat(hours, minutes, longmode)
|
|||||||
ret.before=1
|
ret.before=1
|
||||||
end
|
end
|
||||||
|
|
||||||
if (minutes >= 4) then
|
if (minutes > 4) then
|
||||||
hours=hours+1
|
hours=hours+1
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -97,7 +104,11 @@ function display_timestat(hours, minutes, longmode)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if (hours == 1) then
|
if (hours == 1) then
|
||||||
ret.one=1
|
if (ret.before == 1) then
|
||||||
|
ret.oneLong = 1
|
||||||
|
else
|
||||||
|
ret.one=1
|
||||||
|
end
|
||||||
elseif (hours == 2) then
|
elseif (hours == 2) then
|
||||||
ret.two=1
|
ret.two=1
|
||||||
elseif (hours == 3) then
|
elseif (hours == 3) then
|
||||||
@@ -121,6 +132,85 @@ function display_timestat(hours, minutes, longmode)
|
|||||||
elseif (hours == 12) then
|
elseif (hours == 12) then
|
||||||
ret.twelve=1
|
ret.twelve=1
|
||||||
end
|
end
|
||||||
|
collectgarbage()
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- @fn display_countwords
|
||||||
|
-- Count the amount of characters, used to describe the current time in words
|
||||||
|
-- @param words the same structure, as generated with the function @see display_timestat
|
||||||
|
-- @return the amount of words, used to describe the time or <code>0</code> on errors
|
||||||
|
function display_countwords_de(words)
|
||||||
|
local amount=0
|
||||||
|
if (words.itis == 1) then
|
||||||
|
amount = amount + 5
|
||||||
|
end
|
||||||
|
if (words.fiveMin == 1) then
|
||||||
|
amount = amount + 4
|
||||||
|
end
|
||||||
|
if (words.tenMin == 1) then
|
||||||
|
amount = amount + 4
|
||||||
|
end
|
||||||
|
if (words.twenty == 1) then
|
||||||
|
amount = amount + 7
|
||||||
|
end
|
||||||
|
if (words.threequater == 1) then
|
||||||
|
amount = amount + 11
|
||||||
|
end
|
||||||
|
if (words.quater == 1) then
|
||||||
|
amount = amount + 7
|
||||||
|
end
|
||||||
|
if (words.before == 1) then
|
||||||
|
amount = amount + 3
|
||||||
|
end
|
||||||
|
if (words.after == 1) then
|
||||||
|
amount = amount + 4
|
||||||
|
end
|
||||||
|
if (words.half == 1) then
|
||||||
|
amount = amount + 4
|
||||||
|
end
|
||||||
|
if (words.twelve == 1) then
|
||||||
|
amount = amount + 5
|
||||||
|
end
|
||||||
|
if (words.seven == 1) then
|
||||||
|
amount = amount + 6
|
||||||
|
end
|
||||||
|
if (words.one == 1) then
|
||||||
|
amount = amount + 3
|
||||||
|
end
|
||||||
|
if (words.oneLong == 1) then
|
||||||
|
amount = amount + 4
|
||||||
|
end
|
||||||
|
if (words.two == 1) then
|
||||||
|
amount = amount + 4
|
||||||
|
end
|
||||||
|
if (words.three == 1) then
|
||||||
|
amount = amount + 4
|
||||||
|
end
|
||||||
|
if (words.five == 1) then
|
||||||
|
amount = amount + 4
|
||||||
|
end
|
||||||
|
if (words.four == 1) then
|
||||||
|
amount = amount + 4
|
||||||
|
end
|
||||||
|
if (words.nine == 1) then
|
||||||
|
amount = amount + 4
|
||||||
|
end
|
||||||
|
if (words.eleven == 1) then
|
||||||
|
amount = amount + 3
|
||||||
|
end
|
||||||
|
if (words.eight == 1) then
|
||||||
|
amount = amount + 4
|
||||||
|
end
|
||||||
|
if (words.ten == 1) then
|
||||||
|
amount = amount + 4
|
||||||
|
end
|
||||||
|
if (words.clock == 1) then
|
||||||
|
amount = amount + 3
|
||||||
|
end
|
||||||
|
if (words.six == 1) then
|
||||||
|
amount = amount + 5
|
||||||
|
end
|
||||||
|
|
||||||
|
return amount
|
||||||
|
end
|
||||||
|
Reference in New Issue
Block a user