]> git.gir.st - Ledberg-ESP8266.git/blob - index.cgi
add perl/cgi web app
[Ledberg-ESP8266.git] / index.cgi
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5 use 5.014;
6
7 my $host = "10.42.0.74";
8
9 use IO::Socket;
10
11 my $s = IO::Socket::INET->new(
12 Proto => 'udp',
13 PeerAddr => $host,
14 PeerPort => 1337,
15 Timeout => 1,
16 ) or die "socket";
17
18
19 if ($ENV{QUERY_STRING} =~ /o(n|ff)/) {
20 $s->send(pack("C*", 1, ($1 eq 'n')));
21 } elsif ($ENV{QUERY_STRING} =~ /[0-9a-f]+/i) {
22 my ($r,$g,$b) = unpack("C*", pack("H*",$ENV{QUERY_STRING}));
23 $s->send(pack("C*", 2, $r, $g/2, $b/2));
24 }
25
26 if ($ENV{QUERY_STRING}) {
27 print "status: 204 no content\r\n\r\n";
28 exit 0;
29 }
30
31 my $buf = "";
32 $s->send("\x00");
33 $s->recv($buf,5);
34 my ($ok, $power, $r, $g, $b) = unpack("C*", $buf);
35 my $color = sprintf("%02x%02x%02x", $r, 2*$g, 2*$b);
36
37 print "content-type: text/html\r\n\r\n";
38 print "<script>const initial_color='#$color', initial_power=$power;</script>";
39 print <DATA>;
40
41
42
43 __DATA__
44 <title>ESP8266 Ledberg</title>
45 <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
46 <script src="iro.min.js"></script> <!-- https://iro.js.org/ -->
47
48 <style> /* https://www.w3schools.com/howto/howto_css_switch.asp */
49 .switch {
50 position: relative;
51 display: inline-block;
52 width: 60px;
53 height: 34px;
54 margin:.5em;
55 }
56 .switch input {
57 opacity: 0;
58 width: 0;
59 height: 0;
60 }
61 .slider {
62 position: absolute;
63 cursor: pointer;
64 top: 0;
65 left: 0;
66 right: 0;
67 bottom: 0;
68 background-color: #ccc;
69 -webkit-transition: .4s;
70 transition: .4s;
71 }
72 .slider:before {
73 position: absolute;
74 content: "";
75 height: 26px;
76 width: 26px;
77 left: 4px;
78 bottom: 4px;
79 background-color: white;
80 -webkit-transition: .4s;
81 transition: .4s;
82 }
83 input:checked + .slider {
84 background-color: #2196F3;
85 }
86 input:focus + .slider {
87 box-shadow: 0 0 1px #2196F3;
88 }
89 input:checked + .slider:before {
90 -webkit-transform: translateX(26px);
91 -ms-transform: translateX(26px);
92 transform: translateX(26px);
93 }
94 .slider.round {
95 border-radius: 34px;
96 }
97 .slider.round:before {
98 border-radius: 50%;
99 }
100 .switch { /*custom css*/
101 position: absolute;
102 left: 0;
103 bottom: 34px;
104 margin: 0;
105 }
106 </style>
107
108 <body style="margin:0">
109 <div style="display:flex;flex-direction:column;justify-content:center;align-items:center;text-align:center;min-height:100vh;">
110 <div style="position:relative">
111 <label class="switch"><input id="power" type="checkbox"><span class="slider round"></span></label>
112 <div id="picker"></div>
113 </div>
114 </div>
115
116 <script>
117 "use strict";
118 const hsv2hsl = (h,s,v,l=v-v*s/2, m=Math.min(l,1-l)) => [h,m?(v-l)/m:0,l]; // https://stackoverflow.com/a/54116681
119 const hsv2rgb = (h,s,v,f=((n,k=(n+h/60)%6) => v - v*s*Math.max( Math.min(k,4-k,1), 0))) => [f(5),f(3),f(1)]; // https://stackoverflow.com/a/54024653
120
121 document.querySelector("#power").checked = initial_power;
122 document.querySelector("#power").onchange = e => {
123 fetch('?' + (e.target.checked? 'on' : 'off'));
124 };
125
126 const colorPicker = new iro.ColorPicker('#picker', {
127 wheelLightness: 0,
128 color: initial_color
129 });
130 colorPicker.on(['color:init', 'color:change'], e=>{
131 let [h,s,l] = hsv2hsl(e.hsv.h/360, e.hsv.s/100, 1);
132 document.body.style.background = `hsl(${360*h}deg,${100*s}%,${100*l}%)`;
133 if (window.request) window.request.abort();
134 window.request = new AbortController();
135 fetch(e.hexString.replace('#','?'), {signal:window.request.signal});
136 });
137 </script>
Imprint / Impressum