88 Commits
ntp ... ESP12F

Author SHA1 Message Date
ollo
f79dd867c2 Added RTC module 2017-10-30 17:27:56 +01:00
ollo
bc67988eea ESP Firmware 2.0.0 2017-10-30 17:05:47 +01:00
ollo
b597441192 Boot sequence from both ends 2017-10-27 18:05:53 +02:00
ollo
061b4cff46 More color 2017-03-01 22:04:17 +01:00
ollo
18e2f348a9 Less debug code 2017-03-01 21:46:11 +01:00
ollo
6d3f161b09 There is more color in the text 2017-03-01 21:39:05 +01:00
ollo
f5c3064773 Print WLAN, when searching wifi 2017-03-01 19:53:55 +01:00
ollo
93c6365ef8 Display the amount of characters used to display the time 2017-03-01 19:47:21 +01:00
ollo
3163148238 Moved debug printing line 2017-03-01 19:44:23 +01:00
ollo
6813822f6d Display wordclock function with new parameters: color for minute1 to color for minute2 and amount of characters 2017-03-01 18:55:18 +01:00
ollo
3a55addf66 Removed unsed parameter 2017-03-01 18:51:15 +01:00
ollo
8858bf2289 One in long and short mode are both displayed 2017-03-01 18:32:40 +01:00
ollo
6621dee748 All tests calculating the length of the word passed 2017-03-01 18:28:37 +01:00
ollo
068f4b62e2 More test passed 2017-02-28 19:14:09 +01:00
ollo
1051abbc45 First characters are counted and tested 2017-02-28 19:01:19 +01:00
ollo
24c5d23bef All tests passed (twenty after and twenty for sounds better 2017-02-28 18:52:29 +01:00
ollo
e485f2a0bd More output for the test script 2017-02-28 18:50:43 +01:00
ollo
0085f9ae22 Added new function: count the amount of characters in a time to display (implemented for german) 2017-02-28 18:44:26 +01:00
ollo
467530bec1 Found more code, that is no longer necessary 2017-02-28 18:38:11 +01:00
ollo
4be4e3fcee Moved the three quarter logic into the wordclock module 2017-02-28 18:36:08 +01:00
ollo
0ec3e0c159 More documentation of function 2017-02-28 18:24:38 +01:00
ollo
e42edd7ccc Twenty minutes before is used 2017-01-04 21:54:54 +01:00
ollo
542bd6613d Twenty after is used correct 2017-01-04 21:52:49 +01:00
ollo
2acd9af762 Color is transformed between RGB and GRB 2017-01-04 21:31:57 +01:00
ollo
9adf5b9ed7 Background color can be set 2017-01-03 14:46:09 +01:00
ollo
353e6f0117 Added another parameter to set the background color of the clock 2017-01-03 14:40:03 +01:00
ollo
fba6a90085 Added another parameter to set the background color of the clock 2017-01-03 14:38:17 +01:00
ollo
11bf35f22e Stored color has now also the format: red, green, blue 2017-01-03 14:29:52 +01:00
ollo
b0d64e4140 Immidealty update the variables, when storing a new configuration; Another name for the foreground color in HTML page 2017-01-03 14:27:30 +01:00
ollo
cee1eeb6f3 Updated blacklisted files 2017-01-03 14:26:13 +01:00
ollo
84a36f2c6b Set baud rate to 115200 2017-01-03 14:07:23 +01:00
ollo
4ee159cba3 Try to reduce memory 2017-01-03 13:48:24 +01:00
ollo
a68f7571e7 Stop parsing, when reboot is triggered 2017-01-03 13:38:56 +01:00
ollo
1bbfb7feee Send the answer 5 milliseconds after writing the file 2016-12-30 15:41:19 +01:00
ollo
38e591d061 Clear memory when safing configuration 2016-12-30 14:23:34 +01:00
ollo
4810985a54 Handle uninitialized constants 2016-12-30 14:16:19 +01:00
ollo
b80a604b46 Only try to compile lua files 2016-12-30 13:39:22 +01:00
ollo
687a2bbbb9 More dynamic content is generated 2016-12-29 23:20:40 +01:00
ollo
d2ad06abf1 More HTML5 2016-12-29 22:42:05 +01:00
ollo
8aa34ce408 More content in the page added; parsers skips the amount of read bytes, not the amount of sent bytes 2016-12-29 22:20:19 +01:00
ollo
b99728ada6 Replace constants with dynamic content 2016-12-29 21:57:12 +01:00
ollo
60066bfca2 Comments updated 2016-12-29 21:32:37 +01:00
ollo
d1ad170955 Frubi made me to make it RFC compatible 2016-12-29 21:27:27 +01:00
ollo
3cb00ff3df Webpage can be delivered, once 2016-12-29 21:01:15 +01:00
ollo
7f0d578ca5 prepared sending of one file in multiple parts 2016-12-21 23:56:37 +01:00
C3MA
4b1cea0224 Further webserver stuff 2016-12-17 02:09:23 +01:00
C3MA
cdcd37a997 Started with a new solution where the webpage is fetched from a seperate file 2016-12-14 20:15:25 +01:00
C3MA
a20064bf61 A different color can be selected for each minute 2016-12-14 19:36:59 +01:00
C3MA
093ab81c34 Prepared Minutes in different colors 2016-12-14 19:12:14 +01:00
C3MA
67c506571f added color picker 2016-12-14 18:37:56 +01:00
ollo
8de86b065d Fixed EINS 2016-12-12 20:25:55 +01:00
ollo
a4eda884e3 use the Green,Red,Blue format for the new WS8266 2016-07-03 18:48:46 +02:00
ollo
dc8c5b5361 WS2812 library changed with the last ROM update 2016-07-03 18:41:32 +02:00
ollo
6e8a35307e Automatically reboot the device after the inital flash 2016-07-03 18:41:09 +02:00
ollo
eebe794df2 Documentation for the first setup updated 2016-06-23 20:45:07 +02:00
ollo
141b1b25d9 6k more RAM when used a minimalistic compiled firmware for this use-case 2016-06-23 20:36:21 +02:00
ollo
065caa4ddd Added Script to inital setup an ESP 2016-06-23 18:42:58 +02:00
ollo
28fca5989b Moved scripts around 2016-06-23 18:38:33 +02:00
ollo
28a5bdae85 The WLAN configuration can be done via the Access-Point mode 2016-06-23 18:35:12 +02:00
ollo
10fa0b67a6 Dreiviertel can be activated or deactivated 2016-06-19 23:09:43 +02:00
ollo
d166fb68df Color can be set via the WebInterface 2016-06-19 22:48:44 +02:00
ollo
4ddbebd040 EIN is no longer EINS 2016-06-19 22:23:29 +02:00
ollo
8321e5f112 Directly show the time after finding the WiFi 2016-06-19 18:14:28 +02:00
ollo
b1f702df75 Webserver can be accessed (sometimes... when no Wifi is found, or clock is newly setup 2016-06-19 18:09:33 +02:00
ollo
499cbcbbc5 Setupmode modes! 2016-06-19 17:48:39 +02:00
ollo
1dc2530d38 Moved the custom dofile-logic into the init fmodule 2016-06-19 17:04:30 +02:00
ollo
d9f8d04f55 Extracted the webpage into a seperate file 2016-06-19 16:33:02 +02:00
ollo
d25d3d55a7 More local variables; ~ 2k more RAM 2016-06-19 15:57:57 +02:00
ollo
1c0b5883b9 Work more with even less memory! what a terrible world :-/ 2016-06-19 00:50:18 +02:00
ollo
27ca03878c Timezone calculation ony once 2016-06-19 00:34:30 +02:00
ollo
7140717696 Added time synchronization again 2016-06-19 00:30:09 +02:00
ollo
6874d1545b The code is compiled 2016-06-19 00:08:21 +02:00
ollo
58eed3bef5 cleanup 2016-06-18 23:20:24 +02:00
ollo
4a97dbe0ca So so so! Clean code 2016-06-18 23:19:39 +02:00
ollo
fc8ddab368 Webserver is included into the autostart 2016-06-18 19:46:23 +02:00
ollo
3e5327447b Integrated the configuration generation 2016-06-18 19:35:22 +02:00
ollo
bab4c89d7b Added Boot snake 2016-06-18 19:12:31 +02:00
ollo
07852a6f25 Added Firmware from https://github.com/C3MA/ws2812-clock 2016-06-18 19:11:52 +02:00
ollo
c19d33d24f Color can be set externally 2016-06-18 17:07:49 +02:00
ollo
16b9675a4b Moved logic into seperate file 2016-06-15 21:24:40 +02:00
ollo
0c8ab7155f LEDs are controlled 2016-06-07 23:30:13 +02:00
ollo
b252453f1e Extracted LED generation into seperate function 2016-05-22 15:31:43 +02:00
ollo
309641c023 Merge branch 'master' of https://github.com/0110/Wordclock 2016-05-18 23:06:24 +02:00
ollo
61c97d7a20 When minute4 is reached, all LEDs are set to zero 2016-05-18 23:06:19 +02:00
ollo
67434714ee Integrated wordclock into main 2016-05-18 22:50:56 +02:00
C3MA
53477902c2 Removed unused stuff 2016-05-18 22:25:22 +02:00
ollo
c431d93895 NTP integrated 2016-05-16 13:54:42 +02:00
ollo
1c7f3156ad Prepared main module 2016-05-16 11:15:48 +02:00
20 changed files with 1378 additions and 72 deletions

View File

@@ -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
View 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
View 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
View 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
View 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

View File

@@ -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)

Binary file not shown.

Binary file not shown.

18
os/Readme.md Normal file
View 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

View File

@@ -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
View 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
View File

@@ -0,0 +1,2 @@
# Source:
https://github.com/4refr0nt/luatool/tree/master/luatool

49
tools/initialFlash.sh Executable file
View 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
View 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
View File

View 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
View 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
View 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

View File

@@ -1,3 +0,0 @@
-- Tell the chip to connect to thi access point
wifi.setmode(wifi.STATION)
wifi.sta.config("SSID","password")

View File

@@ -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.before=1
ret.after=1
elseif (minutes==9) then 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.quater = 1
ret.before = 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
if (ret.before == 1) then
ret.oneLong = 1
else
ret.one=1 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