├── .gitignore
├── README.md
├── app
├── ajax
│ ├── display_message.php
│ ├── load_config.php
│ ├── reboot.php
│ └── toggle_relay.php
├── bootstrap.php
├── css
│ ├── app.css
│ ├── fonts.css
│ ├── intro.css
│ └── main.css
├── dashboard.php
├── displays.php
├── fonts
│ ├── montserrat-v14-latin-100.eot
│ ├── montserrat-v14-latin-100.svg
│ ├── montserrat-v14-latin-100.ttf
│ ├── montserrat-v14-latin-100.woff
│ ├── montserrat-v14-latin-100.woff2
│ ├── montserrat-v14-latin-200.eot
│ ├── montserrat-v14-latin-200.svg
│ ├── montserrat-v14-latin-200.ttf
│ ├── montserrat-v14-latin-200.woff
│ ├── montserrat-v14-latin-200.woff2
│ ├── montserrat-v14-latin-300.eot
│ ├── montserrat-v14-latin-300.svg
│ ├── montserrat-v14-latin-300.ttf
│ ├── montserrat-v14-latin-300.woff
│ ├── montserrat-v14-latin-300.woff2
│ ├── montserrat-v14-latin-500.eot
│ ├── montserrat-v14-latin-500.svg
│ ├── montserrat-v14-latin-500.ttf
│ ├── montserrat-v14-latin-500.woff
│ ├── montserrat-v14-latin-500.woff2
│ ├── montserrat-v14-latin-600.eot
│ ├── montserrat-v14-latin-600.svg
│ ├── montserrat-v14-latin-600.ttf
│ ├── montserrat-v14-latin-600.woff
│ ├── montserrat-v14-latin-600.woff2
│ ├── montserrat-v14-latin-800.eot
│ ├── montserrat-v14-latin-800.svg
│ ├── montserrat-v14-latin-800.ttf
│ ├── montserrat-v14-latin-800.woff
│ ├── montserrat-v14-latin-800.woff2
│ ├── montserrat-v14-latin-regular.eot
│ ├── montserrat-v14-latin-regular.svg
│ ├── montserrat-v14-latin-regular.ttf
│ ├── montserrat-v14-latin-regular.woff
│ ├── montserrat-v14-latin-regular.woff2
│ ├── open-sans-v17-latin-300.eot
│ ├── open-sans-v17-latin-300.svg
│ ├── open-sans-v17-latin-300.ttf
│ ├── open-sans-v17-latin-300.woff
│ ├── open-sans-v17-latin-300.woff2
│ ├── open-sans-v17-latin-600.eot
│ ├── open-sans-v17-latin-600.svg
│ ├── open-sans-v17-latin-600.ttf
│ ├── open-sans-v17-latin-600.woff
│ ├── open-sans-v17-latin-600.woff2
│ ├── open-sans-v17-latin-700.eot
│ ├── open-sans-v17-latin-700.svg
│ ├── open-sans-v17-latin-700.ttf
│ ├── open-sans-v17-latin-700.woff
│ ├── open-sans-v17-latin-700.woff2
│ ├── open-sans-v17-latin-800.eot
│ ├── open-sans-v17-latin-800.svg
│ ├── open-sans-v17-latin-800.ttf
│ ├── open-sans-v17-latin-800.woff
│ ├── open-sans-v17-latin-800.woff2
│ ├── open-sans-v17-latin-regular.eot
│ ├── open-sans-v17-latin-regular.svg
│ ├── open-sans-v17-latin-regular.ttf
│ ├── open-sans-v17-latin-regular.woff
│ └── open-sans-v17-latin-regular.woff2
├── img
│ ├── lock.svg
│ ├── mudpi_logo_flat.png
│ ├── mudpi_logo_grad.png
│ ├── mudpi_logo_large_flat.png
│ ├── mudpi_logo_large_grad.png
│ ├── mudpi_logo_small_flat.png
│ ├── mudpi_logo_small_grad.png
│ └── mudpi_logo_white.png
├── index.php
├── js
│ ├── account.js
│ ├── app.js
│ ├── displays.js
│ ├── intro.js
│ ├── relays.js
│ ├── sensor_readings.js
│ └── update_check.js
├── logs.php
├── templates
│ ├── dashboard.php
│ ├── displays.php
│ ├── logs.php
│ ├── modal.php
│ ├── new_account.php
│ ├── partials
│ │ └── navigation.php
│ ├── toggles.php
│ └── welcome.php
└── toggles.php
├── composer.json
├── configs
└── mudpi_ui.conf
└── includes
├── autoloader.php
├── config.php
└── helpers.php
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | scripts/
3 | tests/
4 | vendor/
5 | configs/includes/
6 | package-lock.json
7 | mudpi.config
8 |
9 | # Virtual Environments
10 | .env
11 | .venv
12 | env/
13 | venv/
14 | ENV/
15 | env.bak/
16 | venv.bak/
17 |
18 | # IDE configs
19 | .idea/
20 | .DS_Store
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # MudPi UI
4 | > A lightweight web dashboard to monitor MudPi.
5 |
6 | MudPi UI is a web application that provides an interface to monitor MudPi. The app can read data stored in redis by MudPi and will display the mose recent reading. The dashboard can be accessed from any device on the same network as the pi.
7 |
8 | ## Documentation
9 | For full documentation visit [mudpi.app](https://mudpi.app/docs/setup-assistant)
10 |
11 |
12 | ## Contributing
13 | Any contributions you can make will be greatly appreciated. If you are interested in contributing please get in touch with me and submit a pull request. There is much more I would like to add support for, however being a single developer limits my scope.
14 |
15 |
16 | ## Versioning
17 | Breaking.Major.Minor
18 |
19 |
20 | ## Authors
21 | * Eric Davisson - [Website](http://ericdavisson.com)
22 | * Twitter.com/theDavisson
23 |
24 |
25 | ## License
26 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/ajax/display_message.php:
--------------------------------------------------------------------------------
1 | "Message", //Clear, ClearQueue, Message
27 | "data" => [
28 | "time" => date("Y-m-d H:i:s"),
29 | "message" => $_POST["message"],
30 | "duration" => $_POST["duration"]
31 | ],
32 | "topic" => $_POST["topic"]
33 | );
34 |
35 | //Connecting to Redis server on localhost
36 | $redis = new \Redis();
37 | $redis->connect(MUDPI_REDIS_HOST, MUDPI_REDIS_PORT);
38 |
39 | if($redis->publish($data["topic"], json_encode($data))) {
40 | echo json_encode(['status' => 'OK',
41 | 'message' => 'Successfully Sent Message to Queue',
42 | 'data' => $data]);
43 | }
44 | else {
45 | response_error('Problem Sending Message to Queue');
46 | }
47 |
48 | ?>
49 |
50 |
--------------------------------------------------------------------------------
/app/ajax/load_config.php:
--------------------------------------------------------------------------------
1 | $reading) {
28 | if (!isset($reading["value"])) {
29 | response_error('Reading Value was not set or invalid.');
30 | }
31 |
32 | if (!isset($reading["parsed"]) || empty($reading["parsed"])) {
33 | //response_error('parsed was not set or invalid.');
34 | $reading["parsed"] = null;
35 | }
36 |
37 | if (!isset($reading["sensor"]) || empty($reading["sensor"])) {
38 | //response_error('sensor was not set or invalid.');
39 | $reading["sensor"] = "unknown";
40 | }
41 |
42 | $reading['boots'] = $_POST["boots"];
43 | $reading['source'] = $_POST["source"];
44 | }
45 |
46 |
47 | $data = array(
48 | "time" => date("Y-m-d H:i:s"),
49 | "value" => $_POST["value"],
50 | "parsed" => $_POST["parsed"],
51 | "boots" => $_POST["boots"],
52 | "source" => $_POST["source"]
53 | );
54 |
55 | $old_data = unserialize(file_get_contents("/home/mudpi/sprout.txt"));
56 | $old_data[] = $data;
57 |
58 | if(file_put_contents('/home/mudpi/sprout.txt', serialize($old_data))) {
59 | echo json_encode(['status' => 'OK', 'message' => 'Successfully Saved Readings']);
60 | }
61 | else {
62 | response_error('Problem Saving the Readings to File');
63 | }
64 |
65 | ?>
66 |
67 |
--------------------------------------------------------------------------------
/app/ajax/reboot.php:
--------------------------------------------------------------------------------
1 | '.'.$_POST["key"].".toggle"
18 | );
19 |
20 | //Connecting to Redis server on localhost
21 | $redis = new \Redis();
22 | $redis->connect(MUDPI_REDIS_HOST, MUDPI_REDIS_PORT);
23 |
24 | if($redis->publish('action_call', json_encode($data))) {
25 | echo json_encode(['status' => 'OK', 'message' => 'Successfully Toggled '.$_POST["key"]]);
26 | }
27 | else {
28 | response_error('Problem Toggling the Relay or No Relay Listening');
29 | }
30 |
31 | ?>
32 |
33 |
--------------------------------------------------------------------------------
/app/bootstrap.php:
--------------------------------------------------------------------------------
1 | "",
16 | "humidity" => "%",
17 | "temperature" => "°",
18 | "soil" => "%",
19 | "moisture" => "%",
20 | "float" => "",
21 | "rain" => "%",
22 | "altitude" => '\'',
23 | "pressure" => 'hPa',
24 | "gas" => 'Ω'
25 | ];
26 |
27 | //Connecting to Redis server on localhost
28 | $redis = new Redis();
29 | $redis->connect(MUDPI_REDIS_HOST, MUDPI_REDIS_PORT);
30 |
31 | $started_at = strtotime($redis->get("started_at"));
32 |
33 | // Get the stored keys and print it
34 | $redis_keys = $redis->keys("*");
35 |
36 | $config = json_decode(file_get_contents(MUDPI_PATH_CORE."/".MUDPI_CONFIG_FILE));
37 |
38 | if (!empty($config->sensor)){
39 | foreach($config->sensor as $sensor) {
40 | if(empty($sensor->name)) {
41 | $sensor->name = ucwords(str_replace("_", " ", $sensor->key));
42 | }
43 | if(empty($sensor->classifier)) {
44 | $sensor->classifier = "general";
45 | }
46 | try {
47 | $state = $redis->get($sensor->key.'.state');
48 | if (!empty($state)) {
49 | $sensor->state = json_decode($state);
50 | if (is_json($sensor->state->state)) {
51 | $sensor->state->state = $sensor->state->state;
52 | }
53 | }
54 | else {
55 | throw new Exception('No State Found');
56 | }
57 | } catch (Exception $e) {
58 | $sensor->state = (object)['component_id' => $sensor->key,
59 | 'state' => 0,
60 | 'updated_at' => '',
61 | 'metadata' => ''];
62 | }
63 | }
64 | }
65 |
66 |
67 |
68 | include 'templates/dashboard.php';
69 |
70 | ?>
--------------------------------------------------------------------------------
/app/displays.php:
--------------------------------------------------------------------------------
1 | connect(MUDPI_REDIS_HOST, MUDPI_REDIS_PORT);
15 |
16 | $started_at = strtotime($redis->get("started_at"));
17 |
18 | $config = json_decode(file_get_contents(MUDPI_PATH_CORE."/".MUDPI_CONFIG_FILE));
19 |
20 | $displays = $config->char_display;
21 | foreach($displays as $display) {
22 | if(empty($display->name)) {
23 | $display->name = ucwords(str_replace("_", " ", $display->key));
24 | }
25 | if(empty($display->topic)) {
26 | $display->topic = "char_display/".$display->key;
27 | }
28 |
29 | }
30 |
31 | include 'templates/displays.php';
32 |
33 | ?>
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-100.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-100.eot
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-100.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-100.ttf
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-100.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-100.woff
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-100.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-100.woff2
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-200.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-200.eot
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-200.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-200.ttf
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-200.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-200.woff
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-200.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-200.woff2
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-300.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-300.eot
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-300.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-300.ttf
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-300.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-300.woff
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-300.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-300.woff2
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-500.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-500.eot
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-500.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-500.ttf
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-500.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-500.woff
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-500.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-500.woff2
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-600.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-600.eot
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-600.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
13 |
14 |
15 |
17 |
19 |
22 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
36 |
37 |
38 |
40 |
41 |
43 |
45 |
46 |
49 |
51 |
53 |
55 |
56 |
57 |
58 |
60 |
63 |
64 |
66 |
68 |
69 |
70 |
71 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
82 |
83 |
85 |
86 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
103 |
105 |
107 |
109 |
111 |
112 |
114 |
115 |
116 |
118 |
119 |
120 |
122 |
123 |
125 |
127 |
129 |
130 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
141 |
142 |
144 |
146 |
147 |
148 |
150 |
151 |
153 |
154 |
155 |
158 |
160 |
163 |
165 |
166 |
167 |
168 |
171 |
172 |
174 |
175 |
177 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
187 |
188 |
189 |
191 |
193 |
195 |
196 |
197 |
198 |
200 |
202 |
204 |
205 |
208 |
209 |
210 |
211 |
213 |
214 |
215 |
216 |
218 |
219 |
221 |
223 |
225 |
227 |
230 |
233 |
234 |
236 |
237 |
238 |
239 |
241 |
242 |
243 |
245 |
247 |
249 |
251 |
254 |
257 |
260 |
263 |
265 |
267 |
269 |
271 |
274 |
275 |
276 |
277 |
279 |
281 |
283 |
285 |
287 |
289 |
292 |
295 |
297 |
299 |
300 |
301 |
302 |
304 |
306 |
308 |
310 |
311 |
312 |
313 |
314 |
315 |
317 |
319 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-600.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-600.ttf
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-600.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-600.woff
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-600.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-600.woff2
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-800.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-800.eot
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-800.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
13 |
14 |
15 |
17 |
19 |
22 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
36 |
37 |
39 |
41 |
42 |
44 |
46 |
47 |
50 |
52 |
54 |
56 |
57 |
58 |
59 |
61 |
64 |
65 |
67 |
69 |
70 |
71 |
72 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
83 |
84 |
86 |
87 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
104 |
106 |
108 |
110 |
112 |
113 |
115 |
116 |
117 |
119 |
120 |
121 |
123 |
124 |
126 |
128 |
130 |
131 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
142 |
143 |
145 |
147 |
148 |
149 |
151 |
152 |
154 |
155 |
156 |
159 |
161 |
164 |
166 |
167 |
168 |
169 |
172 |
173 |
175 |
176 |
178 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
188 |
189 |
190 |
192 |
194 |
196 |
197 |
198 |
199 |
201 |
203 |
205 |
206 |
209 |
210 |
211 |
212 |
214 |
215 |
216 |
217 |
219 |
220 |
222 |
224 |
226 |
228 |
231 |
234 |
235 |
237 |
238 |
239 |
240 |
242 |
243 |
244 |
246 |
248 |
250 |
252 |
255 |
258 |
261 |
264 |
266 |
268 |
270 |
272 |
275 |
276 |
277 |
278 |
280 |
282 |
284 |
286 |
288 |
290 |
293 |
296 |
298 |
300 |
301 |
302 |
303 |
305 |
307 |
309 |
311 |
312 |
313 |
314 |
315 |
316 |
318 |
320 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-800.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-800.ttf
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-800.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-800.woff
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-800.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-800.woff2
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-regular.eot
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-regular.ttf
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-regular.woff
--------------------------------------------------------------------------------
/app/fonts/montserrat-v14-latin-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/montserrat-v14-latin-regular.woff2
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-300.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-300.eot
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-300.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-300.ttf
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-300.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-300.woff
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-300.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-300.woff2
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-600.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-600.eot
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-600.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-600.ttf
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-600.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-600.woff
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-600.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-600.woff2
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-700.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-700.eot
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-700.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-700.ttf
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-700.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-700.woff
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-700.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-700.woff2
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-800.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-800.eot
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-800.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-800.ttf
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-800.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-800.woff
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-800.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-800.woff2
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-regular.eot
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-regular.ttf
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-regular.woff
--------------------------------------------------------------------------------
/app/fonts/open-sans-v17-latin-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/fonts/open-sans-v17-latin-regular.woff2
--------------------------------------------------------------------------------
/app/img/lock.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/img/mudpi_logo_flat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/img/mudpi_logo_flat.png
--------------------------------------------------------------------------------
/app/img/mudpi_logo_grad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/img/mudpi_logo_grad.png
--------------------------------------------------------------------------------
/app/img/mudpi_logo_large_flat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/img/mudpi_logo_large_flat.png
--------------------------------------------------------------------------------
/app/img/mudpi_logo_large_grad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/img/mudpi_logo_large_grad.png
--------------------------------------------------------------------------------
/app/img/mudpi_logo_small_flat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/img/mudpi_logo_small_flat.png
--------------------------------------------------------------------------------
/app/img/mudpi_logo_small_grad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/img/mudpi_logo_small_grad.png
--------------------------------------------------------------------------------
/app/img/mudpi_logo_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mudpi/ui/63bc31b8c4f1f52a3b1501e717a026c3571c2815/app/img/mudpi_logo_white.png
--------------------------------------------------------------------------------
/app/index.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/js/account.js:
--------------------------------------------------------------------------------
1 | var app = document.getElementById("app");
2 | var overlay = document.querySelector('.overlay');
3 | var button = document.getElementById("create");
4 | // var button_continue = document.getElementById("continue");
5 | var token_tag = document.getElementById("token");
6 | var errors_list = document.getElementById("errors");
7 | var name_input = document.querySelector('[name="name"]');
8 | var email_input = document.querySelector('[name="email"]');
9 | var pass_input = document.querySelector('[name="password"]');
10 | var pass_confirm_input = document.querySelector('[name="password_confirmation"]');
11 |
12 | setTimeout(function () {
13 | app.classList.remove('transition-out');
14 | overlay.classList.add('transition-out');
15 | }, 300);
16 |
17 | button.addEventListener('click', function() {
18 | var formdata = new FormData();
19 | formdata.append("name", name_input.value);
20 | formdata.append("email", email_input.value);
21 | formdata.append("password", pass_input.value);
22 | formdata.append("password_confirmation", pass_confirm_input.value);
23 | makeRequest('http://mudapi.test/api/register', 'POST', formdata);
24 | });
25 |
26 | function makeRequest(url, type = 'POST' , data = null, callback = null) {
27 | request = new XMLHttpRequest();
28 |
29 | if (!request) {
30 | //Problem making request
31 | return false;
32 | }
33 | if (data === null) {
34 | console.log("Defaulting form data.");
35 | data = new FormData();
36 | }
37 |
38 | button.textContent = "Creating Account...";
39 | button.disabled = true;
40 | button.classList.add('is-grey');
41 | button.classList.remove('is-white');
42 | errors_list.classList.remove("bg-red-light");
43 | errors_list.classList.remove("p-2");
44 |
45 | if (callback === null) {
46 | request.onreadystatechange = handleResponse;
47 | }
48 | else {
49 | request.onreadystatechange = callback;
50 | }
51 | request.open(type, url);
52 | request.setRequestHeader('Accept', 'application/json'); //or application/json;charset=UTF-8
53 | request.send(data);
54 | }
55 |
56 | function handleResponse() {
57 | if (request.readyState === XMLHttpRequest.DONE) {
58 | if (request.status === 200 || request.status === 201) {
59 | var response = JSON.parse(request.responseText).data;
60 | console.log(response);
61 | //Request successful
62 | button.textContent = "Continue";
63 | button.disabled = false;
64 | button.classList.remove('is-grey');
65 | button.classList.add('is-primary');
66 | token_tag.innerHTML = response.token;
67 | document.getElementById('name').innerHTML = response.name;
68 | document.getElementById('email').innerHTML = response.email;
69 | document.getElementById('form').classList.add('transition-out');
70 | setTimeout(function() {
71 | document.getElementById('account').classList.remove('transition-out');
72 | }, 400);
73 |
74 | } else {
75 | var response = JSON.parse(request.responseText);
76 | errors_list.classList.add("bg-red-light");
77 | errors_list.classList.add("p-2");
78 | let errors = `
${response.message}
`;
79 | for (var e in response.errors) {
80 | errors += `${e} - ${response.errors[e][0]} `;
81 | }
82 | errors += ` `;
83 | errors_list.innerHTML = errors;
84 | button.disabled = false;
85 | button.textContent = "Create Account";
86 | button.classList.remove('is-grey');
87 | button.classList.add('is-white');
88 | //Problem with the request (500 error)
89 | }
90 | }
91 | }
--------------------------------------------------------------------------------
/app/js/app.js:
--------------------------------------------------------------------------------
1 | //Ajax for loading in data
2 | var request;
3 | var networks;
4 | var selected_network;
5 | var general_data = new FormData();
6 | var loader = document.getElementById('loader');
7 | var button = document.getElementById("rescan");
8 | var app = document.getElementById("app");
9 | var overlay = document.querySelector('.overlay');
10 |
11 | var modal = document.getElementById("modal");
12 | var ssid_input = document.querySelector('[name="ssid"]');
13 | var passphrase_input = document.querySelector('[name="passphrase1"]');
14 | var passphrase_block = document.getElementById('passphrase_block');
15 | var passphrase_confirm_block = document.getElementById('passphrase_confirm_block');
16 | var button_connect = document.getElementById("connect");
17 | var button_connect_confirm = document.getElementById("connect_confirm");
18 |
19 | document.onkeydown = function(e) {
20 | if (e.key === 'Escape') {
21 | closeModal();
22 | }
23 | }
24 |
25 | setTimeout(function () {
26 | app.classList.remove('transition-out');
27 | overlay.classList.add('transition-out');
28 | }, 300);
29 |
30 | //document.querySelector("#rescan").addEventListener('click', makeRequest);
31 | button.addEventListener('click', function(){ makeRequest('ajax/get_nearby_networks.php', 'POST', general_data); });
32 |
33 | button_connect.addEventListener('click', function() {
34 | if (( selected_network.protocol.localeCompare("Open") != 0 ) && ( passphrase_input.value.length < 8 || passphrase_input.value.length > 64 )) {
35 | passphrase_input.classList.add("b-red-light");
36 | passphrase_input.classList.add("b-1");
37 | document.getElementById("help_message").classList.add("text-red");
38 | document.getElementById("help_message").classList.remove("text-grey");
39 | }
40 | else {
41 | closeModal();
42 | document.getElementById('passphrase').innerHTML = passphrase_input.value;
43 | document.getElementById('ssid').innerHTML = ssid_input.value;
44 | openModal('modal_confirm');
45 | }
46 |
47 | });
48 |
49 | button_connect_confirm.addEventListener('click', function() {
50 | var network_data = new FormData();
51 | network_data.append('ssid', ssid_input.value);
52 | if ( selected_network.protocol.localeCompare("Open") != 0 ) {
53 | network_data.append('passphrase', passphrase_input.value);
54 | }
55 | selected_network.passphrase = passphrase_input.value;
56 | network_data.append('network', JSON.stringify(selected_network));
57 | makeRequest('ajax/connect_to_network.php', 'POST', network_data, handleSaveFileResponse);
58 | });
59 |
60 | function closeModal(id = null) {
61 | let m = null;
62 | if(!id) {
63 | m = document.getElementById("modal");
64 | }
65 | else {
66 | m = document.getElementById(id);
67 | }
68 |
69 | if (m.classList.contains('open')) {
70 | m.classList.toggle('open');
71 | app.classList.toggle('bg-grey-darkest');
72 | app.classList.toggle('opacity-25');
73 | }
74 | }
75 |
76 | function openModal(id = null) {
77 | let m = null;
78 | if(!id) {
79 | m = document.getElementById("modal");
80 | passphrase_input.classList.remove("b-red-light");
81 | passphrase_input.classList.remove("b-1");
82 | document.getElementById("help_message").classList.remove("text-red");
83 | document.getElementById("help_message").classList.add("text-grey");
84 | }
85 | else {
86 | m = document.getElementById(id);
87 | }
88 | if (!m.classList.contains('open')) {
89 | m.classList.toggle('open');
90 | app.classList.toggle('bg-grey-darkest');
91 | app.classList.toggle('opacity-25');
92 |
93 | }
94 | }
95 |
96 | function makeRequest(url, type = 'POST' , data = null, callback = null) {
97 | request = new XMLHttpRequest();
98 |
99 | let old_networks = document.querySelectorAll(`.network`);
100 | old_networks.forEach(net => net.classList.add('transition-out'));
101 | setTimeout(function() {
102 | document.querySelector('#networks').innerHTML = '';
103 | }, 300)
104 |
105 | if (!request) {
106 | //Problem making request
107 | return false;
108 | }
109 | if (data === null) {
110 | console.log("Defaulting form data.");
111 | data = new FormData();
112 | }
113 |
114 | loader.classList.remove('hidden');
115 | button.textContent = "Scanning...";
116 | button.disabled = true;
117 | button.classList.add('is-grey');
118 | button.classList.remove('is-primary');
119 |
120 | if (callback === null) {
121 | request.onreadystatechange = handleResponse;
122 | }
123 | else {
124 | request.onreadystatechange = callback;
125 | }
126 | request.open(type, url);
127 | // request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); //or application/json;charset=UTF-8
128 | setCSRFHeader(request, type, data);
129 | request.send(data);
130 | }
131 |
132 | function handleResponse() {
133 | if (request.readyState === XMLHttpRequest.DONE) {
134 | if (request.status === 200) {
135 | var response = JSON.parse(request.responseText);
136 | networks = response;
137 | //Request successful
138 | loader.classList.add('hidden');
139 | button.textContent = "Rescan";
140 | button.disabled = false;
141 | button.classList.remove('is-grey');
142 | button.classList.add('is-primary');
143 | addResults(response);
144 |
145 | } else {
146 | loader.classList.add('opacity-0');
147 | button.disabled = false;
148 | button.textContent = "Scan Failed. Refresh Page.";
149 | button.classList.remove('is-grey');
150 | button.classList.add('text-white');
151 | button.classList.add('bg-red');
152 | //Problem with the request (500 error)
153 | }
154 | }
155 | }
156 |
157 | function handleSaveFileResponse() {
158 | if (request.readyState === XMLHttpRequest.DONE) {
159 | if (request.status === 200) {
160 | var response = JSON.parse(request.responseText);
161 | //Request successful
162 | closeModal('modal_confirm');
163 | // alert(response.message);
164 |
165 | overlay.classList.remove('transition-out');
166 | loader.classList.add('hidden');
167 | setTimeout(function() {
168 | window.location.href = 'wifi_confirm.php';
169 | }, 700);
170 |
171 |
172 | } else {
173 | alert(request.responseText);
174 | loader.classList.add('hidden');
175 | button_connect_confirm.textContent = "File Save Failed!";
176 | //Problem with the request (500 error)
177 | }
178 | }
179 | }
180 |
181 | function setCSRFHeader(xhr, type, d) {
182 | var csrfToken = document.querySelector('meta[name=csrf_token]').getAttribute('content');
183 | if (/^(POST|PATCH|PUT|DELETE)$/i.test(type)) {
184 | d.append("csrf_token", csrfToken);
185 | xhr.setRequestHeader("X-CSRF-Token", csrfToken);
186 | }
187 | }
188 |
189 | function addResults(results, elm = null) {
190 | if (!results) {
191 | return;
192 | }
193 |
194 | if (!elm) {
195 | elm = document.querySelector('#networks');
196 | }
197 | elm.innerHTML = '';
198 |
199 | let count = 1;
200 | for (var network in results) {
201 | let row = document.createElement('div');
202 | row.id = `network-${count}`
203 | row.dataset.name = results[network]['ssid'];
204 | row.classList.add('network');
205 | row.classList.add('transition-out');
206 | row.classList.add('box');
207 | row.classList.add('mb-3');
208 | row.classList.add('py-2');
209 | row.classList.add('rounded-3');
210 | row.innerHTML = `
211 |
212 |
${results[network]['ssid'].includes('\\x00') ? 'HIDDEN ' : results[network]['ssid']}
213 | ${results[network]['macAddress']}
214 |
215 |
216 | ${results[network]['protocol'] == 'Open' ? '' : '
'}
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
`;
225 | //Connect
226 | elm.append(row);
227 | count++;
228 | }
229 |
230 | setTimeout(function() {
231 | let nets = document.querySelectorAll(`.network`);
232 | nets.forEach(net => net.classList.remove('transition-out'));
233 |
234 | setTimeout(function() {
235 | let bars = document.querySelectorAll(`.wifi-strength .bar`);
236 | bars.forEach(bar => bar.classList.remove('inactive'));
237 | }, 400);
238 | }, 200);
239 |
240 |
241 | var buttons = document.querySelectorAll("#networks .network");
242 |
243 | buttons.forEach(button => button.addEventListener('click', function(e) {
244 | selected_network = networks[this.dataset.name];
245 | ssid_input.value = selected_network.ssid ? selected_network.ssid : '';
246 | passphrase_input.value = selected_network.passphrase ? selected_network.passphrase : '';
247 | if(selected_network.protocol.localeCompare("Open") == 0) {
248 | passphrase_block.style.display = "none";
249 | passphrase_confirm_block.style.display = "none";
250 | }
251 | else {
252 | passphrase_block.style.display = "";
253 | passphrase_confirm_block.style.display = "";
254 | }
255 | openModal(null);
256 | }));
257 |
258 | }
--------------------------------------------------------------------------------
/app/js/displays.js:
--------------------------------------------------------------------------------
1 | var app = document.getElementById("app");
2 | var errors_list = document.getElementById("errors");
3 |
4 | var displays = document.querySelectorAll('.display');
5 |
6 | displays.forEach(display => {
7 | display.querySelector(".send_message").addEventListener('click', function() {
8 | var formdata = new FormData();
9 | formdata.append("message", display.querySelector('[name="message"]').value);
10 | formdata.append("duration", display.querySelector('[name="duration"]').value);
11 | formdata.append("topic", display.querySelector('[name="topic"]').value);
12 | makeRequest('ajax/display_message.php', 'POST', formdata, display.querySelector('.send_message'));
13 | });
14 | });
15 |
16 | function makeRequest(url, type = 'POST' , data = null, button_element = null) {
17 | request = new XMLHttpRequest();
18 |
19 | if (!request) {
20 | //Problem making request
21 | return false;
22 | }
23 | if (data === null) {
24 | console.log("Defaulting form data.");
25 | data = new FormData();
26 | }
27 |
28 | button_element.textContent = "Sending...";
29 | button_element.disabled = true;
30 | button_element.classList.add('is-grey');
31 | button_element.classList.remove('is-primary');
32 | errors_list.classList.remove("bg-red-light");
33 | errors_list.classList.remove("p-2");
34 |
35 | request.onreadystatechange = handle_response(button_element);
36 |
37 | request.open(type, url);
38 | // request.setRequestHeader('Accept', 'application/json'); //or application/json;charset=UTF-8
39 | setCSRFHeader(request, type, data);
40 | request.send(data);
41 | }
42 |
43 | function handle_response(button = null) {
44 | return function() {
45 | if (request.readyState === XMLHttpRequest.DONE) {
46 | if (request.status === 200 || request.status === 201) {
47 | var response = JSON.parse(request.responseText).data;
48 | console.log(response);
49 | //Request successful
50 | button.textContent = "Send Message";
51 | button.disabled = false;
52 | button.classList.remove('is-grey');
53 | button.classList.add('is-primary');
54 |
55 | } else {
56 | var response = JSON.parse(request.responseText);
57 | errors_list.classList.add("bg-red-light");
58 | errors_list.classList.add("p-2");
59 | let errors = `${response.message}
`;
60 | for (var e in response.errors) {
61 | errors += `${e} - ${response.errors[e][0]} `;
62 | }
63 | errors += ` `;
64 | errors_list.innerHTML = errors;
65 | button.disabled = false;
66 | button.textContent = "Create Account";
67 | button.classList.remove('is-grey');
68 | button.classList.add('is-white');
69 | //Problem with the request (500 error)
70 | }
71 | }
72 | };
73 | }
74 |
75 | function setCSRFHeader(xhr, type, d) {
76 | var csrfToken = document.querySelector('meta[name=csrf_token]').getAttribute('content');
77 | if (/^(POST|PATCH|PUT|DELETE)$/i.test(type)) {
78 | d.append("csrf_token", csrfToken);
79 | xhr.setRequestHeader("X-CSRF-Token", csrfToken);
80 | }
81 | }
--------------------------------------------------------------------------------
/app/js/intro.js:
--------------------------------------------------------------------------------
1 | var app = document.getElementById("app");
2 | var button = document.getElementById("continue");
3 | var message = document.getElementById("message");
4 | var title = document.getElementById("title");
5 | var content = document.querySelector(".content");
6 | var overlay = document.querySelector(".overlay");
7 | let step = 0;
8 | let steps = [
9 | 'In the next few steps you will be guided through the MudPi setup process.',
10 | ''
11 |
12 | ];
13 | let titles = [
14 | 'Welcome!',
15 | 'Lets Get Started!'
16 | ];
17 |
18 | setTimeout(function () {
19 | content.classList.remove('transition-out');
20 | app.classList.add('step-1');
21 | }, 600);
22 | setTimeout(function () {
23 | button.classList.remove('transition-out');
24 | }, 2000);
25 |
26 | button.addEventListener('click', function() {
27 | content.classList.add('transition-out');
28 | button.classList.add('transition-out');
29 | if (step >= 1) {
30 | overlay.classList.remove('transition-out');
31 | setTimeout(function() {
32 | window.location.href = 'dashboard.php';
33 | }, 600);
34 | }
35 | else {
36 | app.classList.remove(`step-${step+1}`);
37 | step++;
38 | app.classList.add(`step-${step+1}`);
39 | setTimeout(function() {
40 | message.innerHTML = steps[step];
41 | title.innerHTML = titles[step];
42 | content.classList.remove('transition-out');
43 | setTimeout(function() {
44 | button.classList.remove('transition-out');
45 | }, 600);
46 | }, 400);
47 | }
48 |
49 | });
--------------------------------------------------------------------------------
/app/js/relays.js:
--------------------------------------------------------------------------------
1 | var app = document.getElementById("app");
2 | var errors_list = document.getElementById("errors");
3 |
4 | var relays = document.querySelectorAll('.relay');
5 |
6 | relays.forEach(relay => {
7 | relay.addEventListener('click', function() {
8 | var formdata = new FormData();
9 | formdata.append("key", relay.dataset.key);
10 | formdata.append("topic", relay.dataset.topic);
11 | makeRequest('ajax/toggle_relay.php', 'POST', formdata);
12 | });
13 | });
14 |
15 |
16 | function makeRequest(url, type = 'POST' , data = null, callback = null) {
17 | request = new XMLHttpRequest();
18 |
19 | if (!request) {
20 | //Problem making request
21 | return false;
22 | }
23 | if (data === null) {
24 | console.log("Defaulting form data.");
25 | data = new FormData();
26 | }
27 |
28 | errors_list.classList.remove("bg-red-light");
29 | errors_list.classList.remove("p-2");
30 |
31 | if (callback === null) {
32 | request.onreadystatechange = handleResponse;
33 | }
34 | else {
35 | request.onreadystatechange = callback;
36 | }
37 | request.open(type, url);
38 | // request.setRequestHeader('Accept', 'application/json'); //or application/json;charset=UTF-8
39 | setCSRFHeader(request, type, data);
40 | request.send(data);
41 | }
42 |
43 | function handleResponse() {
44 | if (request.readyState === XMLHttpRequest.DONE) {
45 | if (request.status === 200 || request.status === 201) {
46 | var response = JSON.parse(request.responseText).data;
47 | console.log(response);
48 | //Request successful
49 | setTimeout(() => { location.reload() }, 1500);
50 |
51 | } else {
52 | var response = JSON.parse(request.responseText);
53 | errors_list.classList.add("bg-red-light");
54 | errors_list.classList.add("p-2");
55 | let errors = `${response.message}
`;
56 | for (var e in response.errors) {
57 | errors += `${e} - ${response.errors[e][0]} `;
58 | }
59 | errors += ` `;
60 | errors_list.innerHTML = errors;
61 | //Problem with the request (500 error)
62 | }
63 | }
64 | }
65 |
66 | function setCSRFHeader(xhr, type, d) {
67 | var csrfToken = document.querySelector('meta[name=csrf_token]').getAttribute('content');
68 | if (/^(POST|PATCH|PUT|DELETE)$/i.test(type)) {
69 | d.append("csrf_token", csrfToken);
70 | xhr.setRequestHeader("X-CSRF-Token", csrfToken);
71 | }
72 | }
--------------------------------------------------------------------------------
/app/js/sensor_readings.js:
--------------------------------------------------------------------------------
1 | var app = document.getElementById("app");
2 | var overlay = document.querySelector('.overlay');
3 | var button = document.getElementById("create");
4 | // var button_continue = document.getElementById("continue");
5 | var token_tag = document.getElementById("token");
6 | var errors_list = document.getElementById("errors");
7 | var name_input = document.querySelector('[name="name"]');
8 | var email_input = document.querySelector('[name="email"]');
9 | var pass_input = document.querySelector('[name="password"]');
10 | var pass_confirm_input = document.querySelector('[name="password_confirmation"]');
11 |
12 | setTimeout(function () {
13 | app.classList.remove('transition-out');
14 | overlay.classList.add('transition-out');
15 | }, 300);
16 |
17 | button.addEventListener('click', function() {
18 | var formdata = new FormData();
19 | formdata.append("name", name_input.value);
20 | formdata.append("email", email_input.value);
21 | formdata.append("password", pass_input.value);
22 | formdata.append("password_confirmation", pass_confirm_input.value);
23 | makeRequest('http://mudapi.test/api/register', 'POST', formdata);
24 | });
25 |
26 | function makeRequest(url, type = 'POST' , data = null, callback = null) {
27 | request = new XMLHttpRequest();
28 |
29 | if (!request) {
30 | //Problem making request
31 | return false;
32 | }
33 | if (data === null) {
34 | console.log("Defaulting form data.");
35 | data = new FormData();
36 | }
37 |
38 | button.textContent = "Creating Account...";
39 | button.disabled = true;
40 | button.classList.add('is-grey');
41 | button.classList.remove('is-white');
42 | errors_list.classList.remove("bg-red-light");
43 | errors_list.classList.remove("p-2");
44 |
45 | if (callback === null) {
46 | request.onreadystatechange = handleResponse;
47 | }
48 | else {
49 | request.onreadystatechange = callback;
50 | }
51 | request.open(type, url);
52 | request.setRequestHeader('Accept', 'application/json'); //or application/json;charset=UTF-8
53 | request.send(data);
54 | }
55 |
56 | function handleResponse() {
57 | if (request.readyState === XMLHttpRequest.DONE) {
58 | if (request.status === 200 || request.status === 201) {
59 | var response = JSON.parse(request.responseText).data;
60 | console.log(response);
61 | //Request successful
62 | button.textContent = "Continue";
63 | button.disabled = false;
64 | button.classList.remove('is-grey');
65 | button.classList.add('is-primary');
66 | token_tag.innerHTML = response.token;
67 | document.getElementById('name').innerHTML = response.name;
68 | document.getElementById('email').innerHTML = response.email;
69 | document.getElementById('form').classList.add('transition-out');
70 | setTimeout(function() {
71 | document.getElementById('account').classList.remove('transition-out');
72 | }, 400);
73 |
74 | } else {
75 | var response = JSON.parse(request.responseText);
76 | errors_list.classList.add("bg-red-light");
77 | errors_list.classList.add("p-2");
78 | let errors = `${response.message}
`;
79 | for (var e in response.errors) {
80 | errors += `${e} - ${response.errors[e][0]} `;
81 | }
82 | errors += ` `;
83 | errors_list.innerHTML = errors;
84 | button.disabled = false;
85 | button.textContent = "Create Account";
86 | button.classList.remove('is-grey');
87 | button.classList.add('is-white');
88 | //Problem with the request (500 error)
89 | }
90 | }
91 | }
--------------------------------------------------------------------------------
/app/js/update_check.js:
--------------------------------------------------------------------------------
1 | var app = document.getElementById("app");
2 | var overlay = document.querySelector('.overlay');
3 | var button = document.getElementById("update");
4 | var button_continue = document.getElementById("continue");
5 | var version_tag = document.getElementById("version");
6 | var update_title = document.querySelector('#step-2 h2');
7 |
8 | button.addEventListener("click", function() {
9 | document.querySelector('#step-1').classList.add('transition-out');
10 | button.textContent = "Checking for Updates...";
11 | button.disabled = true;
12 | button.classList.add('is-grey');
13 | button.classList.remove('is-white');
14 | setTimeout(function() {
15 | document.querySelector('#step-1').classList.add('hidden');
16 | document.getElementById('step-2').classList.remove('hidden');
17 | document.getElementById('step-2').classList.remove('transition-out');
18 | makeRequest('ajax/check_for_updates.php')
19 | }, 400);
20 | });
21 |
22 | button_continue.addEventListener('click', function() {
23 | app.classList.add('transition-out');
24 | overlay.classList.remove('transition-out');
25 | setTimeout(function() {
26 | window.location.href = 'new_account.php';
27 | }, 400);
28 | });
29 |
30 | setTimeout(function () {
31 | app.classList.remove('transition-out');
32 | overlay.classList.add('transition-out');
33 | }, 300);
34 |
35 | function makeRequest(url, type = 'GET' , callback = null) {
36 | request = new XMLHttpRequest();
37 |
38 | if (!request) {
39 | //Problem making request
40 | return false;
41 | }
42 |
43 | if (callback === null) {
44 | request.onreadystatechange = handleResponse;
45 | }
46 | else {
47 | request.onreadystatechange = callback;
48 | }
49 | request.open(type, url);
50 | request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); //or application/json;charset=UTF-8
51 | request.send();
52 | }
53 |
54 | function handleResponse() {
55 | if (request.readyState === XMLHttpRequest.DONE) {
56 | if (request.status === 200) {
57 | var response = JSON.parse(request.responseText);
58 | //Request successful
59 | console.log(response);
60 | version_tag.innerHTML = response.available;
61 | if(response.has_updates) {
62 | update_title.innerHTML = "Updates Found!";
63 | setTimeout(function() {
64 | update_title.innerHTML = "Installing Updates...";
65 | makeRequest('ajax/install_updates.php', 'GET', handleUpdateResponse);
66 | }, 3000);
67 | }
68 | else {
69 | update_title.innerHTML = "Already Up to Date!";
70 | setTimeout(function() {
71 | document.getElementById('step-2').classList.add('transition-out');
72 | setTimeout(function() {
73 | document.getElementById('step-2').classList.add('hidden');
74 | document.getElementById('step-3').classList.remove('hidden');
75 | document.getElementById('step-3').classList.remove('transition-out');
76 | }, 500);
77 | }, 3000);
78 | }
79 |
80 | } else {
81 | document.querySelector('#step-2').classList.add('transition-out');
82 | document.querySelector('#step-1').classList.remove('transition-out');
83 | button.disabled = false;
84 | button.textContent = "Update Check Failed. Try Again.";
85 | button.classList.remove('is-grey');
86 | button.classList.add('text-white');
87 | button.classList.add('bg-red');
88 | //Problem with the request (500 error)
89 | }
90 | }
91 | }
92 |
93 | function handleUpdateResponse() {
94 | if (request.readyState === XMLHttpRequest.DONE) {
95 | if (request.status === 200) {
96 | var response = JSON.parse(request.responseText);
97 | //Request successful
98 | console.log(response);
99 | update_title.innerHTML = "Finishing Updates...";
100 | setTimeout(function() {
101 | document.getElementById('step-2').classList.add('transition-out');
102 | setTimeout(function() {
103 | document.getElementById('step-2').classList.add('hidden');
104 | document.getElementById('step-3').classList.remove('hidden');
105 | document.getElementById('step-3').classList.remove('transition-out');
106 | }, 500);
107 | }, 200);
108 |
109 | } else {
110 | document.querySelector('#step-2').classList.add('transition-out');
111 | document.querySelector('#step-1').classList.remove('transition-out');
112 | button.disabled = false;
113 | button.textContent = "Update Check Failed. Try Again.";
114 | button.classList.remove('is-grey');
115 | button.classList.add('text-white');
116 | button.classList.add('bg-red');
117 | //Problem with the request (500 error)
118 | }
119 | }
120 | }
--------------------------------------------------------------------------------
/app/logs.php:
--------------------------------------------------------------------------------
1 |
21 |
22 |
--------------------------------------------------------------------------------
/app/templates/dashboard.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | MudPi Dashboard
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
Dashboard
24 |
System booted ago.
25 |
26 |
27 |
Sensors
28 |
29 | sensor as $sensor) { ?>
30 |
31 |
32 |
name ?? ''; ?>
33 |
interface; ?> -
34 | pin)) { ?>
35 |
Pin: pin; ?>
36 |
37 | address)) { ?>
38 |
0xaddress; ?>
39 |
40 |
41 | state->state)) { foreach($sensor->state->state as $key => $value) { ?>
42 |
46 |
47 |
48 |
state->state ?>classifier]; ?>
49 |
classifier); ?>
50 |
51 |
52 |
53 |
54 |
55 |
Updated: state->updated_at) && $sensor->state->updated_at ) ? timeForHumans(DateTime::createFromFormat('Y-m-d H:i:s', $sensor->state->updated_at)->format('U')) : 'never'?> ago
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/app/templates/displays.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | MudPi Displays
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
Displays
44 |
Control and monitor displays attached to MudPi.
45 |
46 |
47 |
48 |
49 |
50 | $display) { ?>
51 |
52 |
53 |
54 |
55 |
name); ?>
56 |
rows ?? "2"; ?> x columns ?? "16"; ?>
57 |
interface ?>
58 |
59 |
60 |
topic ?? ''; ?>
61 | address)) { ?>
62 |
Address: 0xaddress; ?>
63 |
64 |
65 |
66 |
67 |
68 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/app/templates/logs.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | MudPi UI - Logs
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
Logs
24 |
View the contents of MudPi log Files below.
25 |
26 |
MudPi Logs
27 |
28 |
29 |
MudPi Errors
30 |
31 |
32 |
Auto AP Mode
33 |
34 |
35 |
Wifi Config
36 |
37 |
38 |
Sprout
39 |
$reading) {
51 | if(isset($reading["sensor"])) {
52 | echo $reading["sensor"];
53 | echo "\n";
54 | }
55 | echo $reading["value"]."mV";
56 | echo "\n";
57 | if(isset($reading["parsed"])) {
58 | echo $reading["parsed"]."%";
59 | echo "\n";
60 | }
61 | echo "Boot cycle: ". $reading["boots"];
62 | echo "\n----\n";
63 | }
64 | echo "\n\n";
65 | }
66 | ?>
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/app/templates/modal.php:
--------------------------------------------------------------------------------
1 |
2 |
x (esc)
3 |
4 |
5 | Connect to Network
6 |
7 |
8 |
9 | SSID
10 |
11 |
12 |
13 |
14 |
Password
15 |
16 |
Must be between 8 and 64 characters.
17 |
Show
18 |
19 |
20 |
21 | Connect
22 |
23 |
24 |
25 | Note: Double check your credentials. After a failed connection it can take over 10 minutes before MudPi will reload the hotspot as a fallback.
26 |
27 |
28 |
29 |
30 |
31 |
32 | Everything Look Correct?
33 | MudPi will save the following network configuration and attempt connecting. If wifi connection is offline or fails for over 10 mins the hotspot will be restarted.
34 |
35 |
SSID:
36 |
PASS:
37 |
38 |
39 |
40 |
41 | Cancel
42 | Proceed with Connection
43 |
44 |
--------------------------------------------------------------------------------
/app/templates/new_account.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | MudPi Setup - Create Account
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
46 |
47 |
48 |
49 |
95 |
96 |
97 |
98 |
99 |
Welcome
100 |
Shortly an email will be sent to to confirm your account. Save your access token below somewhere safe. It has been encrypted and will only be shown once. This token is needed when configuring new devices on your account.
101 |
Token:
102 |
You may generate new tokens, but each device will need the new token.
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/app/templates/partials/navigation.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
14 |
15 |
16 |
31 |
32 |
--------------------------------------------------------------------------------
/app/templates/toggles.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | MudPi Relays
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
Toggle
24 |
Toggle components attached to MudPi.
25 |
26 |
27 |
28 |
Toggles
29 |
30 | toggle as $toggle) { ?>
31 |
32 |
33 |
name; ?>
34 | pin)) { ?>
35 |
interface; ?> -
36 |
Pin: pin; ?>
37 |
38 |
(topic; ?>)
39 | key)) { ?>
40 |
key); ?>
41 |
42 |
43 |
44 |
state->state, FILTER_VALIDATE_BOOLEAN) ? "ON" : "OFF" ?>
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/templates/welcome.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | MudPi UI - Dashboard
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
Welcome!
24 |
In the next few steps you will be guided through the MudPi UI setup process.
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/toggles.php:
--------------------------------------------------------------------------------
1 | connect(MUDPI_REDIS_HOST, MUDPI_REDIS_PORT);
15 |
16 | $config = json_decode(file_get_contents(MUDPI_PATH_CORE."/".MUDPI_CONFIG_FILE));
17 |
18 | foreach($config->toggle as $toggle) {
19 | if(empty($toggle->name)) {
20 | $toggle->name = ucwords(str_replace("_", " ", $toggle->key));
21 | }
22 | if(empty($toggle->topic)) {
23 | $toggle->topic = "toggle/".$toggle->key;
24 | }
25 | try {
26 | $state = $redis->get($toggle->key.'.state');
27 | if (!empty($state)) {
28 | $toggle->state = json_decode($state);
29 | }
30 | else {
31 | throw new Exception('No State Found');
32 | }
33 | } catch (Exception $e) {
34 | $toggle->state = (object)['component_id' => $toggle->key,
35 | 'state' => 0,
36 | 'updated_at' => '',
37 | 'metadata' => ''];
38 | }
39 | }
40 |
41 |
42 | include 'templates/toggles.php';
43 |
44 | ?>
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mudpi/ui",
3 | "description": "A lightweight web dashboard to monitor MudPi.",
4 | "version": "0.2.0",
5 | "type": "library",
6 | "keywords": ["mudpi", "garden", "ui", "php", "raspberry pi"],
7 | "homepage": "https://mudpi.app",
8 | "time": "2020-01-01",
9 | "authors": [
10 | {
11 | "name": "Eric Davisson",
12 | "email": "eric@mudpi.app",
13 | "homepage": "http://ericdavisson.com",
14 | "role": "Developer"
15 | }
16 | ],
17 | "support": {
18 | "email": "info@mudpi.app",
19 | "issues": "https://github.com/mudpi/ui/issues",
20 | "source": "https://github.com/mudpi/ui",
21 | "docs": "https://mudpi.app/docs"
22 | },
23 | "autoload": {
24 | "psr-4": {
25 | "Mudpi\\": "app/",
26 | "Mudpi\\Tools\\": "app/tools/",
27 | "Mudpi\\Ajax\\": "app/ajax/"
28 | },
29 | "files": ["includes/helpers.php", "includes/config.php"]
30 | },
31 | "config": {
32 | "sort-packages": true
33 | },
34 | "minimum-stability": "dev",
35 | "prefer-stable": true
36 | }
--------------------------------------------------------------------------------
/configs/mudpi_ui.conf:
--------------------------------------------------------------------------------
1 | # Default server configuration for mudpi ui
2 | server {
3 | listen 80 default_server;
4 | listen [::]:80 default_server;
5 |
6 | root /var/www/html/mudpi/app;
7 | index index.php index.html index.htm;
8 |
9 | server_name _ mudpi.home;
10 |
11 | location / {
12 | try_files $uri $uri/ /index.php?$query_string;
13 | }
14 |
15 | # define error page
16 | error_page 404 = @notfound;
17 |
18 | location @notfound {
19 | return 302 $scheme://mudpi.home;
20 | }
21 |
22 | #Dont log images or noneresources
23 | location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
24 | access_log off;
25 | log_not_found off;
26 | expires 360d;
27 | }
28 |
29 | ## Begin - Security
30 | # deny all direct access for these folders
31 | location ~* /(.git|cache|bin|logs|backups|tests)/.*$ { return 403; }
32 |
33 | # deny running scripts inside core system folders
34 | location ~* /(system|vendor)/.*\.(txt|xml|md|html|yaml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
35 |
36 | # deny running scripts inside user folder
37 | location ~* /user/.*\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
38 |
39 | # deny access to specific files in the root folder
40 | location ~ /(LICENSE.txt|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess) { return 403; }
41 |
42 | # deny access to .htaccess files, if Apache's document root
43 | # concurs with nginx's one
44 | location ~ /\.ht {
45 | deny all;
46 | }
47 | ## End - Security
48 |
49 | ## Begin - PHP
50 | location ~ \.php$ {
51 | fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
52 | #fastcgi_pass unix:/run/php/php7.0-fpm.sock;
53 | fastcgi_split_path_info ^(.+\.php)(/.+)$;
54 | fastcgi_index index.php;
55 | fastcgi_intercept_errors on; #captive portal
56 | include fastcgi_params;
57 | fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
58 | }
59 | }
--------------------------------------------------------------------------------
/includes/autoloader.php:
--------------------------------------------------------------------------------
1 | ';
33 | }
34 |
35 | function csrf_meta() {
36 | $token = htmlspecialchars($_SESSION['csrf_token']);
37 | return ' ';
38 | }
39 |
40 | function csrf_token() {
41 | $token = htmlspecialchars($_SESSION['csrf_token']);
42 | return $token;
43 | }
44 |
45 | function validate_csrf_token() {
46 | $csrf_token = $_POST['csrf_token'] ?? null;
47 | $header_token = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? null;
48 |
49 | //Check if a token is even set
50 | if (empty($csrf_token) && empty($header_token)) {
51 | return false;
52 | }
53 |
54 | //Check to see if there is a post token otherwise use the server token.
55 | $request_token = $csrf_token ?: $header_token;
56 |
57 | return hash_equals($_SESSION['csrf_token'], $request_token);
58 | }
59 |
60 | function handle_invalid_csrf()
61 | {
62 | response_error('Invalid CSRF token or session expired');
63 | }
64 |
65 | function response_error($error = "There was an error.")
66 | {
67 | header('HTTP/1.1 500 Internal Server Error');
68 | header('Content-Type: text/plain');
69 | echo $error;
70 | exit;
71 | }
72 |
73 | //Used to parse general configrations like key value files or lighthttp
74 | function parseConfig($configuration) {
75 | $config = array();
76 | foreach ($configuration as $line) {
77 | $line = trim($line);
78 | if ($line == "" || $line[0] == "#") {
79 | continue; //skip empty lines and comments
80 | }
81 | //Fancy way to spit config file on the '=' and trim the values
82 | list($option, $value) = array_map("trim", explode("=", $line, 2));
83 |
84 | if (empty($config[$option])) {
85 | $config[$option] = $value ?: null;
86 | } else {
87 | if (!is_array($config[$option])) {
88 | $config[$option] = [ $config[$option] ];
89 | }
90 | $config[$option][] = $value;
91 | }
92 | }
93 | return $config;
94 | }
95 |
96 | // Helpers for system commands and fetching system info
97 | function getConnectedNetworkName() {
98 | exec("iwgetid ". MUDPI_WIFI_INTERFACE . ' -r', $name);
99 | return $name;
100 | }
101 |
102 | function getNetworkInfo() {
103 | exec("ls /sys/class/net | grep -v lo", $interfaces);
104 | foreach ($interfaces as $interface) {
105 | exec("ip a show $interface", $$interface);
106 | }
107 | return $interfaces;
108 | }
109 |
110 | function reboot() {
111 | $result = shell_exec("sudo /sbin/reboot");
112 | return $result;
113 | }
114 |
115 | function shutdown() {
116 | $result = shell_exec("sudo /sbin/shutdown -h now");
117 | return $result; //Not going to get this message ever...
118 | }
119 |
120 | function getCurrentDirectory() {
121 | exec('pwd', $directory);
122 | return $directory;
123 | }
124 |
125 | function switchDirectory($directory) {
126 | if (isset($directory)) {
127 | exec("cd ".$directory);
128 | }
129 | }
130 |
131 | function makeDirectory($directory, $createParentDirectories = false) {
132 | if (isset($directory)) {
133 | if($createParentDirectories) {
134 | $result = exec("mkdir ".$directory. " -p");
135 | }
136 | else {
137 | $result = exec("mkdir ".$directory);
138 | }
139 | return $result;
140 | }
141 | return false;
142 | }
143 |
144 | function listFiles($path = null) {
145 | if($path) {
146 | exec("ls ".$path." -lah", $results);
147 | }
148 | else {
149 | exec("ls -lah", $results);
150 | }
151 | return $results;
152 | }
153 |
154 | function timeForHumans ($time)
155 | {
156 |
157 | $time = time() - $time; // to get the time since that moment
158 | $time = ($time<1)? 1 : $time;
159 | $tokens = array (
160 | 31536000 => 'year',
161 | 2592000 => 'month',
162 | 604800 => 'week',
163 | 86400 => 'day',
164 | 3600 => 'hour',
165 | 60 => 'minute',
166 | 1 => 'second'
167 | );
168 |
169 | foreach ($tokens as $unit => $text) {
170 | if ($time < $unit) continue;
171 | $numberOfUnits = floor($time / $unit);
172 | return $numberOfUnits.' '.$text.(($numberOfUnits>1)?'s':'');
173 | }
174 | }
175 |
176 | function slug($string, $spacer = "_"){
177 | return strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', $spacer, $string), $spacer));
178 | }
179 |
180 | function parseReading($type = "general", $value = null) {
181 | $type = strtolower($type);
182 | switch($type) {
183 | case "humidity":
184 | return json_decode($value);
185 | break;
186 | case "bme680":
187 | // {"temperature": 66.5, "humidity": 59.9, "pressure": 994.01, "gas": 36187, "altitude": 161.457}
188 | return json_decode($value);
189 | break;
190 | case "soil":
191 | return [ "Moisture" => $value ];
192 | break;
193 | case "float":
194 | return [ "Float" => $value ];
195 | break;
196 | case "temperature":
197 | return [ "Temperature" => $value ];
198 | break;
199 | case "rain":
200 | return [ "Rain" => $value ];
201 | break;
202 | default:
203 | return [ "General" => $value ];
204 | break;
205 | }
206 | }
207 |
208 | function is_json($string) {
209 | json_decode($string);
210 | return (json_last_error() == JSON_ERROR_NONE);
211 | }
--------------------------------------------------------------------------------