initial commit
This commit is contained in:
commit
d7af96fcfa
6 changed files with 327 additions and 0 deletions
15
access_point.py
Normal file
15
access_point.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import network #importing network
|
||||||
|
import gc
|
||||||
|
|
||||||
|
|
||||||
|
gc.collect()
|
||||||
|
ssid = 'PicoClock' #Set access point name
|
||||||
|
password = 'ayalaido' #Set your access point password
|
||||||
|
|
||||||
|
ap = network.WLAN(network.AP_IF)
|
||||||
|
ap.config(essid=ssid, password=password, hostname="pico.clock")
|
||||||
|
ap.active(True) #activating
|
||||||
|
|
||||||
|
print('AccessPoint Up And Running!')
|
||||||
|
print(ap.ifconfig())
|
||||||
|
|
85
index.html
Normal file
85
index.html
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body onload="startTime()">
|
||||||
|
<header>
|
||||||
|
<h1>PicoClock</h1>
|
||||||
|
<p>Ayala & Ido's Clock Settings</p>
|
||||||
|
<p> State: <b><span id="time"></span></b> | 🌞Day: <span class="{day_light_class}">💡</span> | 🌚Night: <span
|
||||||
|
class="{night_light_class}">💡</span></p>
|
||||||
|
<nav> <a href="#" onclick="setTime()">🕰️ Set Time</a> <a href="#" onclick="toggle('day')">🌞 Toggle</a> <a
|
||||||
|
href="#" onclick="toggle('night')">🌚 Toggle</a> </nav>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<p> Working Mode: </p>
|
||||||
|
<input type="radio" id="auto" value="auto" {mode_auto} onclick="update_mode('auto')">
|
||||||
|
<label for="auto">Schedule</label>
|
||||||
|
<br>
|
||||||
|
<input type="radio" id="manual" value="manual" {mode_manual} onclick="update_mode('manual')">
|
||||||
|
<label for="manual">Manual</label><br>
|
||||||
|
<hr>
|
||||||
|
<div style="display: flex;">
|
||||||
|
<div style="width: 100%;">
|
||||||
|
<p>🌞 💡Is set to: {day_on_time}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="display:flex"> <input type="time" id="N2D" style="width:100%"> <button type="foo"
|
||||||
|
onclick="set_time_update('day', 'N2D')">SET</button> </div>
|
||||||
|
<div style="display: flex;">
|
||||||
|
<div style="width: 100%;">
|
||||||
|
<p>🌚💡Is set to: {night_on_time}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="display:flex"> <input type="time" id="D2N" style="width: 100%;"> <button type="foo"
|
||||||
|
onclick="set_time_update('night', 'D2N')">SET</button> </div>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
<p>Made with ❤️ by <a href="mailto:picoclock@sagi.dayanhub.com">ZeGoomba</a>. v0.0.1</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
function toggle(time) {
|
||||||
|
fetch(`/toggle_${time}/`).finally(reload).catch(console.error);
|
||||||
|
}
|
||||||
|
function setTime() {
|
||||||
|
d = new Date();
|
||||||
|
fetch(`/stime/${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}/`).finally(reload).catch(console.error);
|
||||||
|
}
|
||||||
|
function update_mode(mode) {
|
||||||
|
fetch(`/update_mode/${mode}/`).finally(reload).catch(console.error);
|
||||||
|
}
|
||||||
|
function set_time_update(time, id) {
|
||||||
|
let el = document.getElementById(id);
|
||||||
|
let [h, m] = el.value.split(':').map(v => parseInt(v));
|
||||||
|
if (h && m) fetch(`/set_${time}_time/${h}/${m}/`).finally(reload).catch(console.error);
|
||||||
|
}
|
||||||
|
function startTime() {
|
||||||
|
let time = new Date();
|
||||||
|
time.setHours({time_h});
|
||||||
|
time.setMinutes({time_m});
|
||||||
|
time.setSeconds({time_s});
|
||||||
|
timeLoop(time);
|
||||||
|
}
|
||||||
|
function timeLoop(time) {
|
||||||
|
let h = time.getHours();
|
||||||
|
let m = time.getMinutes();
|
||||||
|
let s = time.getSeconds();
|
||||||
|
m = checkTime(m);
|
||||||
|
s = checkTime(s);
|
||||||
|
document.getElementById('time').innerHTML = h + ":" + m + ":" + s;
|
||||||
|
setTimeout(timeLoop, 1000, new Date(time.getTime() + 1000));
|
||||||
|
}
|
||||||
|
function checkTime(i) {
|
||||||
|
if (i < 10) {i = "0" + i};
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
function reload() {
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html>
|
104
io_state.py
Normal file
104
io_state.py
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
import machine
|
||||||
|
|
||||||
|
rtc = machine.RTC()
|
||||||
|
|
||||||
|
class State:
|
||||||
|
def __init__(self):
|
||||||
|
self._auto_mode = False
|
||||||
|
self._day_on = False
|
||||||
|
self._day_on_time = [6, 30]
|
||||||
|
self._day_off_time = [19, 0]
|
||||||
|
rtc.datetime((2018, 10, 15, 1, 13, 11, 0, 0)) #(year, month, day, weekday, hours, minutes, seconds, subseconds)
|
||||||
|
self._current_time = rtc.datetime()
|
||||||
|
self._current_time = (2018, 20, 15, 1, 13, 11, 0, 0)
|
||||||
|
self._night_on = False
|
||||||
|
|
||||||
|
self._day_pins = [
|
||||||
|
machine.Pin("LED", machine.Pin.OUT)
|
||||||
|
]
|
||||||
|
self._night_pins = []
|
||||||
|
for pin in self._day_pins + self._night_pins:
|
||||||
|
pin.off()
|
||||||
|
|
||||||
|
def is_day_on(self):
|
||||||
|
return self._day_on
|
||||||
|
|
||||||
|
def is_night_on(self):
|
||||||
|
return self._night_on
|
||||||
|
|
||||||
|
def is_auto_mode(self):
|
||||||
|
return self._auto_mode
|
||||||
|
|
||||||
|
def set_auto_mode(self, is_set):
|
||||||
|
self._auto_mode = is_set
|
||||||
|
|
||||||
|
def toggle_day(self):
|
||||||
|
print("=> Toggle day")
|
||||||
|
for pin in self._day_pins:
|
||||||
|
pin.toggle()
|
||||||
|
self._day_on = not self._day_on
|
||||||
|
|
||||||
|
def toggle_night(self):
|
||||||
|
print("=> Toggle night")
|
||||||
|
for pin in self._night_pins:
|
||||||
|
pin.toggle()
|
||||||
|
self._night_on = not self._night_on
|
||||||
|
|
||||||
|
def set_time(self, h, m, s):
|
||||||
|
rtc.datetime((2018, 10, 15, 1, h, m, s, 0))
|
||||||
|
|
||||||
|
def set_times(self, is_day, h, m):
|
||||||
|
if is_day:
|
||||||
|
self._day_on_time = [h, m]
|
||||||
|
else:
|
||||||
|
self._day_off_time = [h, m]
|
||||||
|
|
||||||
|
def switch_to_day(self, is_day):
|
||||||
|
if is_day:
|
||||||
|
if not self._day_on:
|
||||||
|
self.toggle_day()
|
||||||
|
if self._night_on:
|
||||||
|
self.toggle_night()
|
||||||
|
else:
|
||||||
|
if self._day_on:
|
||||||
|
self.toggle_day()
|
||||||
|
if not self._night_on:
|
||||||
|
self.toggle_night()
|
||||||
|
|
||||||
|
def get_time_h(self):
|
||||||
|
return self._current_time[4]
|
||||||
|
|
||||||
|
def get_time_m(self):
|
||||||
|
return self._current_time[5]
|
||||||
|
|
||||||
|
def get_time_s(self):
|
||||||
|
return self._current_time[6]
|
||||||
|
|
||||||
|
def get_day_on_time(self):
|
||||||
|
return self._day_on_time
|
||||||
|
|
||||||
|
def get_day_off_time(self):
|
||||||
|
return self._day_off_time
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
self._current_time = rtc.datetime()
|
||||||
|
if self._auto_mode:
|
||||||
|
c_h = self._current_time[4]
|
||||||
|
c_m = self._current_time[5]
|
||||||
|
day_h = self._day_on_time[0]
|
||||||
|
day_m = self._day_on_time[1]
|
||||||
|
night_h = self._day_off_time[0]
|
||||||
|
night_m = self._day_off_time[1]
|
||||||
|
if day_h < c_h < night_h: # Hours (day_on < current < night on)
|
||||||
|
self.switch_to_day(True)
|
||||||
|
elif day_h == c_h and day_m <= c_m:
|
||||||
|
self.switch_to_day(True)
|
||||||
|
elif night_h == c_h and c_m < night_m:
|
||||||
|
self.switch_to_day(True)
|
||||||
|
else:
|
||||||
|
self.switch_to_day(False)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
state = State()
|
||||||
|
|
14
main.py
Normal file
14
main.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import machine
|
||||||
|
|
||||||
|
import io_state
|
||||||
|
import access_point
|
||||||
|
from webserver import accept_connection
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
accept_connection()
|
||||||
|
io_state.state.update()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
machine.reset()
|
||||||
|
|
13
style.css
Normal file
13
style.css
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
:root{--sans-font:-apple-system,BlinkMacSystemFont,"Avenir Next",Avenir,"Nimbus Sans L",Roboto,Noto,"Segoe UI",Arial,Helvetica,"Helvetica Neue",sans-serif;--mono-font:Consolas,Menlo,Monaco,"Andale Mono","Ubuntu Mono",monospace;--base-fontsize:1.15rem;--header-scale:1.25;--line-height:1.618;--bg:#fff;--accent-bg:#f5f7ff;--text:#212121;--text-light:#585858;--border:#d8dae1;--accent:#0d47a1;--accent-light:#90caf9;--code:#d81b60;--preformatted:#444;--marked:#ffdd33;--disabled:#efefef}@media (prefers-color-scheme:dark){:root{--bg:#212121;--accent-bg:#2b2b2b;--text:#dcdcdc;--text-light:#ababab;--border:#666;--accent:#ffb300;--accent-light:#ffecb3;--code:#f06292;--preformatted:#ccc;--disabled:#111}}html{font-family:var(--sans-font)}body{color:var(--text);background:var(--bg);font-size:var(--base-fontsize);line-height:var(--line-height);display:flex;min-height:100vh;flex-direction:column;flex:1;margin:0 auto;max-width:45rem;padding:0 .5rem;overflow-x:hidden;word-break:break-word;overflow-wrap:break-word}header{background:var(--accent-bg);border-bottom:1px solid var(--border);text-align:center;padding:2rem .5rem;width:100vw;position:relative;box-sizing:border-box;left:50%;right:50%;margin-left:-50vw;margin-right:-50vw}header h1,header p{margin:0}main{padding-top:1.5rem}h1,h2,h3{line-height:1.1}nav{font-size:1rem;line-height:2;padding:1rem 0}nav a{margin:1rem 1rem 0 0;border:1px solid var(--border);border-radius:5px;color:var(--text)!important;display:inline-block;padding:.1rem 1rem;text-decoration:none;transition:.4s}nav a:hover{color:var(--accent)!important;border-color:var(--accent)}footer{margin-top:4rem;padding:2rem 1rem 1.5rem 1rem;color:var(--text-light);font-size:.9rem;text-align:center;border-top:1px solid var(--border)}h1{font-size:calc(var(--base-fontsize) * var(--header-scale) * var(--header-scale) * var(--header-scale) * var(--header-scale));margin-top:calc(var(--line-height) * 1.5rem)}h2{font-size:calc(var(--base-fontsize) * var(--header-scale) * var(--header-scale) * var(--header-scale));margin-top:calc(var(--line-height) * 1.5rem)}h3{font-size:calc(var(--base-fontsize) * var(--header-scale) * var(--header-scale));margin-top:calc(var(--line-height) * 1.5rem)}h4{font-size:calc(var(--base-fontsize) * var(--header-scale));margin-top:calc(var(--line-height) * 1.5rem)}h5{font-size:var(--base-fontsize);margin-top:calc(var(--line-height) * 1.5rem)}h6{font-size:calc(var(--base-fontsize)/ var(--header-scale));margin-top:calc(var(--line-height) * 1.5rem)}a,a:visited{color:var(--accent)}a:hover{text-decoration:none}[role=button],a button,button,input[type=button],input[type=reset],input[type=submit]{border:none;border-radius:5px;background:var(--accent);font-size:1rem;color:var(--bg);padding:.7rem .9rem;margin:.5rem 0;transition:.4s}[role=button][aria-disabled=true],a button[disabled],button[disabled],input[type=button][disabled],input[type=checkbox][disabled],input[type=radio][disabled],input[type=reset][disabled],input[type=submit][disabled]{cursor:default;opacity:.5;cursor:not-allowed}input:disabled{cursor:not-allowed;background-color:var(--disabled)}input[type=range]{padding:0}[role=button]:focus,[role=button]:not([aria-disabled=true]):hover,button:enabled:hover,button:focus,input[type=button]:enabled:hover,input[type=button]:focus,input[type=checkbox]:enabled:hover,input[type=checkbox]:focus,input[type=radio]:enabled:hover,input[type=radio]:focus,input[type=reset]:enabled:hover,input[type=reset]:focus,input[type=submit]:enabled:hover,input[type=submit]:focus{filter:brightness(1.4);cursor:pointer}input{font-size:inherit;font-family:inherit;padding:.5rem;margin-bottom:.5rem;color:var(--text);background:var(--bg);border:1px solid var(--border);border-radius:5px;box-shadow:none;box-sizing:border-box;width:60%;-moz-appearance:none;-webkit-appearance:none;appearance:none}input[type=checkbox],input[type=radio]{vertical-align:bottom;position:relative}input[type=radio]{border-radius:100%}input[type=checkbox]:checked,input[type=radio]:checked{background:var(--accent)}input[type=checkbox]:checked::after{content:" ";width:.1em;height:.25em;border-radius:0;position:absolute;top:.05em;left:.18em;background:0 0;border-right:solid var(--bg) .08em;border-bottom:solid var(--bg) .08em;font-size:1.8em;transform:rotate(45deg)}input[type=radio]:checked::after{content:" ";width:.25em;height:.25em;border-radius:100%;position:absolute;top:.125em;background:var(--bg);left:.125em;font-size:32px}@media only screen and (max-width:720px){input{width:100%}}input[type=checkbox],input[type=radio]{width:auto}input[type=file]{border:0}hr{color:var(--border);border-top:1px;margin:1rem auto}button{width:100%;margin:0 5px 5px 5px}.grayscale{filter:grayscale(1)}
|
||||||
|
nav a{
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
footer {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
font-family: "Roboto", "Apple Color Emoji", 'Noto Sans Symbols 2', Helvetica, Arial, sans-serif;
|
||||||
|
}
|
96
webserver.py
Normal file
96
webserver.py
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
import re
|
||||||
|
try:
|
||||||
|
import usocket as socket #importing socket
|
||||||
|
except:
|
||||||
|
import socket
|
||||||
|
|
||||||
|
from io_state import state
|
||||||
|
|
||||||
|
css_file = open('style.css', 'r')
|
||||||
|
css = css_file.read()
|
||||||
|
css_file.close()
|
||||||
|
|
||||||
|
html_file = open("index.html", "r")
|
||||||
|
html = html_file.read()
|
||||||
|
html_file.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def web_page():
|
||||||
|
return html \
|
||||||
|
.replace("{day_light_class}", "" if state.is_day_on() else "grayscale") \
|
||||||
|
.replace("{night_light_class}", "" if state.is_night_on() else "grayscale") \
|
||||||
|
.replace("{time_h}", str(state.get_time_h())) \
|
||||||
|
.replace("{time_m}", str(state.get_time_m())) \
|
||||||
|
.replace("{time_s}", str(state.get_time_s())) \
|
||||||
|
.replace("{mode_auto}", "checked" if state.is_auto_mode() else "") \
|
||||||
|
.replace("{mode_manual}", "" if state.is_auto_mode() else "checked") \
|
||||||
|
.replace("{day_on_time}", f"{state.get_day_on_time()[0]:02}:{state.get_day_on_time()[1]:02}") \
|
||||||
|
.replace("{night_on_time}", f"{state.get_day_off_time()[0]:02}:{state.get_day_off_time()[1]:02}") \
|
||||||
|
|
||||||
|
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #creating socket object
|
||||||
|
s.bind(('0.0.0.0', 80))
|
||||||
|
s.listen(5)
|
||||||
|
s.settimeout(0.5)
|
||||||
|
|
||||||
|
def accept_connection():
|
||||||
|
try:
|
||||||
|
global s
|
||||||
|
conn, addr = s.accept()
|
||||||
|
request = str(conn.recv(1024))
|
||||||
|
|
||||||
|
if request.find('/style.css') >= 0:
|
||||||
|
conn.send(css)
|
||||||
|
conn.close()
|
||||||
|
return
|
||||||
|
elif request.find('/update_mode/auto/') >= 0:
|
||||||
|
print("Update mode to auto.")
|
||||||
|
state.set_auto_mode(True)
|
||||||
|
elif request.find('/update_mode/manual/') >= 0:
|
||||||
|
print("Update mode to manual.")
|
||||||
|
state.set_auto_mode(False)
|
||||||
|
|
||||||
|
elif request.find('/stime/') >= 0:
|
||||||
|
timestamp_regex = re.compile(r'stime\/(\d+):(\d+):(\d+)\/')
|
||||||
|
h = int(timestamp_regex.search(request).group(1))
|
||||||
|
m = int(timestamp_regex.search(request).group(2))
|
||||||
|
_s = int(timestamp_regex.search(request).group(3))
|
||||||
|
print(f"Changing current time to: {h}:{m}:{_s}")
|
||||||
|
state.set_time(h, m, _s)
|
||||||
|
|
||||||
|
elif request.find('/toggle_day/') >= 0:
|
||||||
|
print("toggle day")
|
||||||
|
state.set_auto_mode(False)
|
||||||
|
state.toggle_day()
|
||||||
|
elif request.find('/toggle_night/') >= 0:
|
||||||
|
print("toggle night.")
|
||||||
|
state.set_auto_mode(False)
|
||||||
|
state.toggle_night()
|
||||||
|
|
||||||
|
elif request.find('/set_day_time/') >= 0:
|
||||||
|
times_regex = re.compile(r'time\/(\d+)\/(\d+)/')
|
||||||
|
h = int(times_regex.search(request).group(1))
|
||||||
|
m = int(times_regex.search(request).group(2))
|
||||||
|
print(f'Changing time for day_on to {h}:{m}')
|
||||||
|
state.set_times(True, h, m)
|
||||||
|
elif request.find('/set_night_time/') >= 0:
|
||||||
|
times_regex = re.compile(r'time\/(\d+)\/(\d+)/')
|
||||||
|
h = int(times_regex.search(request).group(1))
|
||||||
|
m = int(times_regex.search(request).group(2))
|
||||||
|
print(f'Changing time for day_off to {h}:{m}')
|
||||||
|
state.set_times(False, h, m)
|
||||||
|
|
||||||
|
response = web_page()
|
||||||
|
conn.send(response)
|
||||||
|
conn.close()
|
||||||
|
except OSError as e:
|
||||||
|
try:
|
||||||
|
conn.close()
|
||||||
|
print(f'ERROR: connection closed: {e}')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue