Voice Controlled Arduino
Control your Arduino project from anywhere using your mobile or home voice assistant!
Components and supplies
ESP32
Apps and platforms
Assistant SDK
Arduino IDE
Visual Micro
Maker service
Visual Studio 2017
Project description
Code
normalize.css
css
Responsive CSS to support web page. For ESP place in "sketchFolder\data" for upload via SPIFFS
1/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 3/** 4 * 1. Set default font family to sans-serif. 5 * 2. Prevent iOS text size adjust after orientation change, without disabling 6 * user zoom. 7 */ 8 9html { 10 font-family: sans-serif; /* 1 */ 11 -ms-text-size-adjust: 100%; /* 2 */ 12 -webkit-text-size-adjust: 100%; /* 2 */ 13} 14 15/** 16 * Remove default margin. 17 */ 18 19body { 20 margin: 0; 21} 22 23/* HTML5 display definitions 24 ========================================================================== */ 25 26/** 27 * Correct `block` display not defined for any HTML5 element in IE 8/9. 28 * Correct `block` display not defined for `details` or `summary` in IE 10/11 29 * and Firefox. 30 * Correct `block` display not defined for `main` in IE 11. 31 */ 32 33article, 34aside, 35details, 36figcaption, 37figure, 38footer, 39header, 40hgroup, 41main, 42menu, 43nav, 44section, 45summary { 46 display: block; 47} 48 49/** 50 * 1. Correct `inline-block` display not defined in IE 8/9. 51 * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 */ 53 54audio, 55canvas, 56progress, 57video { 58 display: inline-block; /* 1 */ 59 vertical-align: baseline; /* 2 */ 60} 61 62/** 63 * Prevent modern browsers from displaying `audio` without controls. 64 * Remove excess height in iOS 5 devices. 65 */ 66 67audio:not([controls]) { 68 display: none; 69 height: 0; 70} 71 72/** 73 * Address `[hidden]` styling not present in IE 8/9/10. 74 * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. 75 */ 76 77[hidden], 78template { 79 display: none; 80} 81 82/* Links 83 ========================================================================== */ 84 85/** 86 * Remove the gray background color from active links in IE 10. 87 */ 88 89a { 90 background-color: transparent; 91} 92 93/** 94 * Improve readability when focused and also mouse hovered in all browsers. 95 */ 96 97a:active, 98a:hover { 99 outline: 0; 100} 101 102/* Text-level semantics 103 ========================================================================== */ 104 105/** 106 * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 107 */ 108 109abbr[title] { 110 border-bottom: 1px dotted; 111} 112 113/** 114 * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 115 */ 116 117b, 118strong { 119 font-weight: bold; 120} 121 122/** 123 * Address styling not present in Safari and Chrome. 124 */ 125 126dfn { 127 font-style: italic; 128} 129 130/** 131 * Address variable `h1` font-size and margin within `section` and `article` 132 * contexts in Firefox 4+, Safari, and Chrome. 133 */ 134 135h1 { 136 font-size: 2em; 137 margin: 0.67em 0; 138} 139 140/** 141 * Address styling not present in IE 8/9. 142 */ 143 144mark { 145 background: #ff0; 146 color: #000; 147} 148 149/** 150 * Address inconsistent and variable font size in all browsers. 151 */ 152 153small { 154 font-size: 80%; 155} 156 157/** 158 * Prevent `sub` and `sup` affecting `line-height` in all browsers. 159 */ 160 161sub, 162sup { 163 font-size: 75%; 164 line-height: 0; 165 position: relative; 166 vertical-align: baseline; 167} 168 169sup { 170 top: -0.5em; 171} 172 173sub { 174 bottom: -0.25em; 175} 176 177/* Embedded content 178 ========================================================================== */ 179 180/** 181 * Remove border when inside `a` element in IE 8/9/10. 182 */ 183 184img { 185 border: 0; 186} 187 188/** 189 * Correct overflow not hidden in IE 9/10/11. 190 */ 191 192svg:not(:root) { 193 overflow: hidden; 194} 195 196/* Grouping content 197 ========================================================================== */ 198 199/** 200 * Address margin not present in IE 8/9 and Safari. 201 */ 202 203figure { 204 margin: 1em 40px; 205} 206 207/** 208 * Address differences between Firefox and other browsers. 209 */ 210 211hr { 212 -moz-box-sizing: content-box; 213 box-sizing: content-box; 214 height: 0; 215} 216 217/** 218 * Contain overflow in all browsers. 219 */ 220 221pre { 222 overflow: auto; 223} 224 225/** 226 * Address odd `em`-unit font size rendering in all browsers. 227 */ 228 229code, 230kbd, 231pre, 232samp { 233 font-family: monospace, monospace; 234 font-size: 1em; 235} 236 237/* Forms 238 ========================================================================== */ 239 240/** 241 * Known limitation: by default, Chrome and Safari on OS X allow very limited 242 * styling of `select`, unless a `border` property is set. 243 */ 244 245/** 246 * 1. Correct color not being inherited. 247 * Known issue: affects color of disabled elements. 248 * 2. Correct font properties not being inherited. 249 * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 */ 251 252button, 253input, 254optgroup, 255select, 256textarea { 257 color: inherit; /* 1 */ 258 font: inherit; /* 2 */ 259 margin: 0; /* 3 */ 260} 261 262/** 263 * Address `overflow` set to `hidden` in IE 8/9/10/11. 264 */ 265 266button { 267 overflow: visible; 268} 269 270/** 271 * Address inconsistent `text-transform` inheritance for `button` and `select`. 272 * All other form control elements do not inherit `text-transform` values. 273 * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 * Correct `select` style inheritance in Firefox. 275 */ 276 277button, 278select { 279 text-transform: none; 280} 281 282/** 283 * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 * and `video` controls. 285 * 2. Correct inability to style clickable `input` types in iOS. 286 * 3. Improve usability and consistency of cursor style between image-type 287 * `input` and others. 288 */ 289 290button, 291html input[type="button"], /* 1 */ 292input[type="reset"], 293input[type="submit"] { 294 -webkit-appearance: button; /* 2 */ 295 cursor: pointer; /* 3 */ 296} 297 298/** 299 * Re-set default cursor for disabled elements. 300 */ 301 302button[disabled], 303html input[disabled] { 304 cursor: default; 305} 306 307/** 308 * Remove inner padding and border in Firefox 4+. 309 */ 310 311button::-moz-focus-inner, 312input::-moz-focus-inner { 313 border: 0; 314 padding: 0; 315} 316 317/** 318 * Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 * the UA stylesheet. 320 */ 321 322input { 323 line-height: normal; 324} 325 326/** 327 * It's recommended that you don't attempt to style these elements. 328 * Firefox's implementation doesn't respect box-sizing, padding, or width. 329 * 330 * 1. Address box sizing set to `content-box` in IE 8/9/10. 331 * 2. Remove excess padding in IE 8/9/10. 332 */ 333 334input[type="checkbox"], 335input[type="radio"] { 336 box-sizing: border-box; /* 1 */ 337 padding: 0; /* 2 */ 338} 339 340/** 341 * Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 * `font-size` values of the `input`, it causes the cursor style of the 343 * decrement button to change from `default` to `text`. 344 */ 345 346input[type="number"]::-webkit-inner-spin-button, 347input[type="number"]::-webkit-outer-spin-button { 348 height: auto; 349} 350 351/** 352 * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 * 2. Address `box-sizing` set to `border-box` in Safari and Chrome 354 * (include `-moz` to future-proof). 355 */ 356 357input[type="search"] { 358 -webkit-appearance: textfield; /* 1 */ 359 -moz-box-sizing: content-box; 360 -webkit-box-sizing: content-box; /* 2 */ 361 box-sizing: content-box; 362} 363 364/** 365 * Remove inner padding and search cancel button in Safari and Chrome on OS X. 366 * Safari (but not Chrome) clips the cancel button when the search input has 367 * padding (and `textfield` appearance). 368 */ 369 370input[type="search"]::-webkit-search-cancel-button, 371input[type="search"]::-webkit-search-decoration { 372 -webkit-appearance: none; 373} 374 375/** 376 * Define consistent border, margin, and padding. 377 */ 378 379fieldset { 380 border: 1px solid #c0c0c0; 381 margin: 0 2px; 382 padding: 0.35em 0.625em 0.75em; 383} 384 385/** 386 * 1. Correct `color` not being inherited in IE 8/9/10/11. 387 * 2. Remove padding so people aren't caught out if they zero out fieldsets. 388 */ 389 390legend { 391 border: 0; /* 1 */ 392 padding: 0; /* 2 */ 393} 394 395/** 396 * Remove default vertical scrollbar in IE 8/9/10/11. 397 */ 398 399textarea { 400 overflow: auto; 401} 402 403/** 404 * Don't inherit the `font-weight` (applied by a rule above). 405 * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 406 */ 407 408optgroup { 409 font-weight: bold; 410} 411 412/* Tables 413 ========================================================================== */ 414 415/** 416 * Remove most spacing between table cells. 417 */ 418 419table { 420 border-collapse: collapse; 421 border-spacing: 0; 422} 423 424td, 425th { 426 padding: 0; 427}
data\Index.html
html
Web Page for data partition of ESP board (or PROGMEM / Webserver). For ESP place in "sketchFolder\data" for upload via SPIFFS Uses simple responsive framework (included in other files)
1<HTML> 2<HEAD> 3 <!-- Basic Page Needs --> 4 <meta charset="utf-8"> 5 <title>ESP Web App</title> 6 <meta name="description" content="Starting you Off with IoT"> 7 <meta name="author" content="vMicro"> 8 9 <!-- Mobile Specific Metas --> 10 <meta name="viewport" content="width=device-width, initial-scale=1; maximum-scale=5.0; user-scalable=0;"> 11 <meta name="apple-mobile-web-app-capable" content="yes" /> 12 13 <!-- CSS --> 14 <link rel="stylesheet" href="normalize.css"> 15 <link rel="stylesheet" href="skeleton.css"> 16 17 <!-- Client Scripts --> 18 <script type="text/javascript" src="/ClientSideScript.js"></script> 19</HEAD> 20<BODY> 21 22 <div class="container"> 23 <div class="row"> 24 <h2>Embedded SPIFFS ESP Application (8266/8285/32)</h2> 25 <p>About as simple as it can be made, and all simplistic, easy to edit code.....</p> 26 </div> 27 <div class="row"> 28 <button id="on" class="button-primary">1-1 On</button> 29 <button id="off">1-1 Off</button> 30 </div> 31 <div class="row"> 32 <div>Response: <span id="infoPanel"></span></div> 33 </div> 34 </div> 35</BODY> 36 37 38</HTML> 39
skeleton.css
css
Responsive CSS to support web page. For ESP place in "sketchFolder\data" for upload via SPIFFS
1/* 2* Skeleton V2.0.4 3* Copyright 2014, Dave Gamache 4* www.getskeleton.com 5* Free to use under the MIT license. 6* http://www.opensource.org/licenses/mit-license.php 7* 12/29/2014 8*/ 9 10 11/* Table of contents 12 13- Grid 14- Base Styles 15- Typography 16- Links 17- Buttons 18- Forms 19- Lists 20- Code 21- Tables 22- Spacing 23- Utilities 24- Clearing 25- Media Queries 26*/ 27 28 29/* Grid 30 */ 31.container { 32 position: relative; 33 width: 100%; 34 max-width: 960px; 35 margin: 0 auto; 36 padding: 0 20px; 37 box-sizing: border-box; } 38.column, 39.columns { 40 width: 100%; 41 float: left; 42 box-sizing: border-box; } 43 44/* For devices larger than 400px */ 45@media (min-width: 400px) { 46 .container { 47 width: 85%; 48 padding: 0; } 49} 50 51/* For devices larger than 550px */ 52/* HACKED To ensure it remains the same on mobile */ 53@media (min-width: 320px) { 54 .container { 55 width: 80%; } 56 .column, 57 .columns { 58 margin-left: 4%; } 59 .column:first-child, 60 .columns:first-child { 61 margin-left: 0; } 62 63 .one.column, 64 .one.columns { width: 4.66666666667%; } 65 .two.columns { width: 13.3333333333%; } 66 .three.columns { width: 22%; } 67 .four.columns { width: 30.6666666667%; } 68 .five.columns { width: 39.3333333333%; } 69 .six.columns { width: 48%; } 70 .seven.columns { width: 56.6666666667%; } 71 .eight.columns { width: 65.3333333333%; } 72 .nine.columns { width: 74.0%; } 73 .ten.columns { width: 82.6666666667%; } 74 .eleven.columns { width: 91.3333333333%; } 75 .twelve.columns { width: 100%; margin-left: 0; } 76 77 .one-third.column { width: 30.6666666667%; } 78 .two-thirds.column { width: 65.3333333333%; } 79 80 .one-half.column { width: 48%; } 81 82 /* Offsets */ 83 .offset-by-one.column, 84 .offset-by-one.columns { margin-left: 8.66666666667%; } 85 .offset-by-two.column, 86 .offset-by-two.columns { margin-left: 17.3333333333%; } 87 .offset-by-three.column, 88 .offset-by-three.columns { margin-left: 26%; } 89 .offset-by-four.column, 90 .offset-by-four.columns { margin-left: 34.6666666667%; } 91 .offset-by-five.column, 92 .offset-by-five.columns { margin-left: 43.3333333333%; } 93 .offset-by-six.column, 94 .offset-by-six.columns { margin-left: 52%; } 95 .offset-by-seven.column, 96 .offset-by-seven.columns { margin-left: 60.6666666667%; } 97 .offset-by-eight.column, 98 .offset-by-eight.columns { margin-left: 69.3333333333%; } 99 .offset-by-nine.column, 100 .offset-by-nine.columns { margin-left: 78.0%; } 101 .offset-by-ten.column, 102 .offset-by-ten.columns { margin-left: 86.6666666667%; } 103 .offset-by-eleven.column, 104 .offset-by-eleven.columns { margin-left: 95.3333333333%; } 105 106 .offset-by-one-third.column, 107 .offset-by-one-third.columns { margin-left: 34.6666666667%; } 108 .offset-by-two-thirds.column, 109 .offset-by-two-thirds.columns { margin-left: 69.3333333333%; } 110 111 .offset-by-one-half.column, 112 .offset-by-one-half.columns { margin-left: 52%; } 113 114} 115 116 117/* Base Styles 118 */ 119/* NOTE 120html is set to 62.5% so that all the REM measurements throughout Skeleton 121are based on 10px sizing. So basically 1.5rem = 15px :) */ 122html { 123 font-size: 62.5%; } 124body { 125 font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */ 126 line-height: 1.6; 127 font-weight: 400; 128 font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; 129 color: #222; } 130 131 132/* Typography 133 */ 134h1, h2, h3, h4, h5, h6 { 135 margin-top: 0; 136 margin-bottom: 2rem; 137 font-weight: 300; } 138h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;} 139h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; } 140h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; } 141h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; } 142h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; } 143h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; } 144 145/* Larger than phablet */ 146@media (min-width: 550px) { 147 h1 { font-size: 5.0rem; } 148 h2 { font-size: 4.2rem; } 149 h3 { font-size: 3.6rem; } 150 h4 { font-size: 3.0rem; } 151 h5 { font-size: 2.4rem; } 152 h6 { font-size: 1.5rem; } 153} 154 155p { 156 margin-top: 0; } 157 158 159/* Links 160 */ 161a { 162 color: #1EAEDB; } 163a:hover { 164 color: #0FA0CE; } 165 166 167/* Buttons 168 */ 169.button, 170button, 171input[type="submit"], 172input[type="reset"], 173input[type="button"] { 174 display: inline-block; 175 height: 38px; 176 padding: 0 30px; 177 color: #555; 178 text-align: center; 179 font-size: 11px; 180 font-weight: 600; 181 line-height: 38px; 182 letter-spacing: .1rem; 183 text-transform: uppercase; 184 text-decoration: none; 185 white-space: nowrap; 186 background-color: transparent; 187 border-radius: 4px; 188 border: 1px solid #bbb; 189 cursor: pointer; 190 box-sizing: border-box; } 191.button:hover, 192button:hover, 193input[type="submit"]:hover, 194input[type="reset"]:hover, 195input[type="button"]:hover, 196.button:focus, 197button:focus, 198input[type="submit"]:focus, 199input[type="reset"]:focus, 200input[type="button"]:focus { 201 color: #333; 202 border-color: #888; 203 outline: 0; } 204.button.button-primary, 205button.button-primary, 206input[type="submit"].button-primary, 207input[type="reset"].button-primary, 208input[type="button"].button-primary { 209 color: #FFF; 210 background-color: #33C3F0; 211 border-color: #33C3F0; } 212.button.button-primary:hover, 213button.button-primary:hover, 214input[type="submit"].button-primary:hover, 215input[type="reset"].button-primary:hover, 216input[type="button"].button-primary:hover, 217.button.button-primary:focus, 218button.button-primary:focus, 219input[type="submit"].button-primary:focus, 220input[type="reset"].button-primary:focus, 221input[type="button"].button-primary:focus { 222 color: #FFF; 223 background-color: #1EAEDB; 224 border-color: #1EAEDB; } 225 226 227/* Forms 228 */ 229input[type="email"], 230input[type="number"], 231input[type="search"], 232input[type="text"], 233input[type="tel"], 234input[type="url"], 235input[type="password"], 236textarea, 237select { 238 height: 38px; 239 padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */ 240 background-color: #fff; 241 border: 1px solid #D1D1D1; 242 border-radius: 4px; 243 box-shadow: none; 244 box-sizing: border-box; } 245/* Removes awkward default styles on some inputs for iOS */ 246input[type="email"], 247input[type="number"], 248input[type="search"], 249input[type="text"], 250input[type="tel"], 251input[type="url"], 252input[type="password"], 253textarea { 254 -webkit-appearance: none; 255 -moz-appearance: none; 256 appearance: none; } 257textarea { 258 min-height: 65px; 259 padding-top: 6px; 260 padding-bottom: 6px; } 261input[type="email"]:focus, 262input[type="number"]:focus, 263input[type="search"]:focus, 264input[type="text"]:focus, 265input[type="tel"]:focus, 266input[type="url"]:focus, 267input[type="password"]:focus, 268textarea:focus, 269select:focus { 270 border: 1px solid #33C3F0; 271 outline: 0; } 272label, 273legend { 274 display: block; 275 margin-bottom: .5rem; 276 font-weight: 600; } 277fieldset { 278 padding: 0; 279 border-width: 0; } 280input[type="checkbox"], 281input[type="radio"] { 282 display: inline; } 283label > .label-body { 284 display: inline-block; 285 margin-left: .5rem; 286 font-weight: normal; } 287 288 289/* Lists 290 */ 291ul { 292 list-style: circle inside; } 293ol { 294 list-style: decimal inside; } 295ol, ul { 296 padding-left: 0; 297 margin-top: 0; } 298ul ul, 299ul ol, 300ol ol, 301ol ul { 302 margin: 1.5rem 0 1.5rem 3rem; 303 font-size: 90%; } 304li { 305 margin-bottom: 1rem; } 306 307 308/* Code 309 */ 310code { 311 padding: .2rem .5rem; 312 margin: 0 .2rem; 313 font-size: 90%; 314 white-space: nowrap; 315 background: #F1F1F1; 316 border: 1px solid #E1E1E1; 317 border-radius: 4px; } 318pre > code { 319 display: block; 320 padding: 1rem 1.5rem; 321 white-space: pre; } 322 323 324/* Tables 325 */ 326th, 327td { 328 padding: 12px 15px; 329 text-align: left; 330 border-bottom: 1px solid #E1E1E1; } 331th:first-child, 332td:first-child { 333 padding-left: 0; } 334th:last-child, 335td:last-child { 336 padding-right: 0; } 337 338 339/* Spacing 340 */ 341button, 342.button { 343 margin-bottom: 1rem; } 344input, 345textarea, 346select, 347fieldset { 348 margin-bottom: 1.5rem; } 349pre, 350blockquote, 351dl, 352figure, 353table, 354p, 355ul, 356ol, 357form { 358 margin-bottom: 2.5rem; } 359 360 361/* Utilities 362 */ 363.u-full-width { 364 width: 100%; 365 box-sizing: border-box; } 366.u-max-full-width { 367 max-width: 100%; 368 box-sizing: border-box; } 369.u-pull-right { 370 float: right; } 371.u-pull-left { 372 float: left; } 373 374 375/* Misc 376 */ 377hr { 378 margin-top: 3rem; 379 margin-bottom: 3.5rem; 380 border-width: 0; 381 border-top: 1px solid #E1E1E1; } 382 383 384/* Clearing 385 */ 386 387/* Self Clearing Goodness */ 388.container:after, 389.row:after, 390.u-cf { 391 content: ""; 392 display: table; 393 clear: both; } 394 395 396/* Media Queries 397 */ 398/* 399Note: The best way to structure the use of media queries is to create the queries 400near the relevant code. For example, if you wanted to change the styles for buttons 401on small devices, paste the mobile query code up in the buttons section and style it 402there. 403*/ 404 405 406/* Larger than mobile */ 407@media (min-width: 400px) {} 408 409/* Larger than phablet (also point when grid becomes active) */ 410@media (min-width: 550px) {} 411 412/* Larger than tablet */ 413@media (min-width: 750px) {} 414 415/* Larger than desktop */ 416@media (min-width: 1000px) {} 417 418/* Larger than Desktop HD */ 419@media (min-width: 1200px) {} 420
Arduino Example Software for ESP32/ESP8266
arduino
Example software which is triggered by Google Assistant and turns on / off a power socket. Also has web UI which allows for web page control of the socket as well. Change headers if using a different board
1/* 2 Name: ESP32_WebServerApp_Example.ino 3 Created: 3/14/2019 12:06:43 AM 4 Author: Simon 5 6 Simple WebApp on SPIFFS Served Locally via mDNS Name or IP 7 Example #1 - RF Lightswitches - ESP32 as WiFi Client, Simple AJAX Requests or whole page loads for now (no WS yet) 8 9 Upload and go to http://esp32.local (or inspect Serial monitor if connecting via IP) 10 11 */ 12#ifdef ESP32 13 #include <spiffs.h> 14 #include <WiFi.h> 15 #include <ESPmDNS.h> 16 #define FORMAT_SPIFFS_IF_FAILED false // You may have to set this to true the first time you run this 17#endif 18 19#ifdef ESP8266 20 #include <FS.h> 21 #include <ESP8266WiFi.h> 22 #include <ESP8266mDNS.h> 23 #define FORMAT_SPIFFS_IF_FAILED // Leave Empty on ESP8266 24#endif 25 26#include <RCSwitch.h> 27 28// WiFi Client Settings 29const char* ssid = "**************"; 30const char* password = "**************"; 31const char* mDnsName = "esp32"; 32const byte hwPin_rfTx = 2; 33 34WiFiServer server(9090); 35RCSwitch mySwitch = RCSwitch(); 36File root; 37void setup() { 38 Serial.begin(115200); 39 delay(5000); 40 // Setup our File System in SPIFFS 41 if (!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)) { 42 Serial.println("SPIFFS Mount Failed"); 43 return; 44 } 45 root = SPIFFS.open("/", "r"); 46 47 // Static IP Configuration 48 IPAddress local_IP(192, 168, 0, 55); 49 IPAddress gateway(192, 168, 0, 1); 50 IPAddress subnet(255, 255, 255, 0); 51 IPAddress primaryDNS(192, 168, 0, 1); 52 IPAddress secondaryDNS(8, 8, 4, 4); // fake 53 54 WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS); 55 56 // Setup the Web Connection 57 WiFi.begin(ssid, password); 58 59 Serial.println(F("Connecting to Wifi. ")); 60 while (!WL_CONNECTED || WiFi.localIP().toString() == "0.0.0.0") { 61 delay(500); // Yield() sdasdasdasd 62 Serial.print(". "); 63 } 64 65 // Setup our Remote Controlled Wall Socket 66 mySwitch.enableTransmit(2); 67 Serial.print("Connected to "); 68 Serial.print(ssid); 69 Serial.print(" on IP address: "); 70 Serial.println(WiFi.localIP()); 71 72 // Set up mDNS responder: 73 // - first argument is the domain name, in this example 74 // the fully-qualified domain name is "mDnsName.local" 75 if (!MDNS.begin(mDnsName)) { 76 Serial.println("Error setting up MDNS responder!"); 77 } 78 else { 79 Serial.println("mDNS responder started"); 80 } 81 82 // Finally startup the web server 83 server.begin(); 84 Serial.println("TCP server started."); 85 86 // Bind the HTTP requests via MDNS 87 MDNS.addService("http", "tcp", 9090); 88} 89 90 91void loop(void) { 92 WiFiClient client = server.available(); // listen for incoming clients 93 94 if (client) { // Someone is talking to us... 95 96 97 String currentLine = ""; // make a String to hold incoming data from the client 98 while (client.connected()) { // loop while the client's connected 99 100 String req = client.readStringUntil('\ '); // Read the first line of HTTP request 101 102 // First line of HTTP request looks like "GET /path HTTP/1.1" 103 // Retrieve the "/path" part by finding the spaces 104 int addr_start = req.indexOf(' '); 105 int addr_end = req.indexOf(' ', addr_start + 1); 106 if (addr_start == -1 || addr_end == -1) { 107 Serial.print("Invalid request: "); 108 Serial.println(req); 109 break; 110 } 111 req = req.substring(addr_start + 1, addr_end); 112 Serial.print("Request: "); 113 Serial.println(req); 114 115 // Set Access Control Policy to allow CORS (Not actually needed here at present...) 116 client.println("HTTP/1.1 200 OK\ \ 117Access-Control-Allow-Origin: *\ \ 118Content-Type: text/html\ \ 119\ \ 120"); 121 handleFileRead(req, client); 122 } 123 124 // close the connection: 125 client.stop(); 126 Serial.println("Client Disconnected."); 127 } 128} 129 130// Handle all the content types we may get asked for from our SPIFFS 131String getContentType(String filename) { 132 if (filename.endsWith(".htm")) return "text/html"; 133 else if (filename.endsWith(".html")) return "text/html"; 134 else if (filename.endsWith(".css")) return "text/css"; 135 else if (filename.endsWith(".js")) return "application/javascript"; 136 else if (filename.endsWith(".png")) return "image/png"; 137 else if (filename.endsWith(".gif")) return "image/gif"; 138 else if (filename.endsWith(".jpg")) return "image/jpeg"; 139 else if (filename.endsWith(".ico")) return "image/x-icon"; 140 else if (filename.endsWith(".xml")) return "text/xml"; 141 return "text/plain"; 142} 143 144// Handle a File request either via our custom handlers, or simply serving a file... 145bool handleFileRead(String path, WiFiClient &client) { 146 Serial.println("handleFileRead: " + path); 147 if (path.endsWith("/")) path += "index.html"; // If a folder is requested, send the index file 148 String contentType = getContentType(path); // Get the MIME type 149 150 // Simple hardcoding for now but can easily be expanded into the below 151 // If we used a command with a number it would map in but "turn the light 1" sounds odd.. 152 if (path.startsWith("/on")) { 153 mySwitch.switchOn(1, 1); 154 } 155 else if (path.startsWith("/off")) { 156 mySwitch.switchOff(1, 1); 157 } 158 else 159 // Handle our "custom" (non-file) requests first 160 // We Expect the URL in format /socket/1/1/1 meaning:Socket 1, Address 1, Action ON 161 if (path.startsWith("/socket/")) { 162 int socket = path.charAt(8) - 48; 163 int address = path.charAt(10) - 48; 164 int action = path.charAt(12) - 48; 165 166 client.print("Socket "); 167 client.print(socket); 168 client.print(":"); 169 client.print(address); 170 171 if (action == 1) { 172 mySwitch.switchOn(socket, address); 173 client.println(" ON"); 174 return true; 175 } 176 else { 177 mySwitch.switchOff(socket, address); 178 client.println(" OFF"); 179 return true; 180 } 181 } 182 else if (SPIFFS.exists(path)) { // If the file exists 183 File file = SPIFFS.open(path, "r"); // Open it 184 client.print(file.readStringUntil(EOF)); // Read Until End Of File back to client 185 file.close(); // Then close the file again 186 return true; 187 } 188 189 Serial.println("\ File Not Found"); 190 client.print("<b>Invalid Request</b>"); // Show the user some info on web page 191 return false; // If the file doesn't exist, return false 192} 193
ClientSideScript.js
javascript
Client JS to support web page. For ESP place in "sketchFolder\data" for upload via SPIFFS
1// Everything in pure JS to save codespace for your preferred Libs 2window.addEventListener("load", onWindowLoad); 3 4// This all kicks in when the page lands on the client browser 5function onWindowLoad() { 6 console.log("Page Loaded"); 7 // Add some Listeners to our buttons to send requests back 8 document.getElementById("on").addEventListener("click", sendOnRequest); 9 document.getElementById("off").addEventListener("click", sendOffRequest); 10} 11 12function sendOnRequest() { 13 sendAjaxRequest( 14 function () { 15 document.getElementById("infoPanel").innerHTML = this.responseText; 16 } 17 , "GET" 18 , "/socket/1/1/1" 19 ); 20} 21 22function sendOffRequest() { 23 sendAjaxRequest( 24 function () { 25 document.getElementById("infoPanel").innerHTML = this.responseText; 26 } 27 , "GET" 28 , "/socket/1/1/0" 29 ); 30} 31 32// Generic wrapper to send requests to the server 33function sendAjaxRequest(onReplyFunction, method, url) { 34 var xhttp = new XMLHttpRequest() 35 // What happens when the server replies with an answer 36 xhttp.onreadystatechange = function () { 37 if (this.readyState == 4 && this.status == 200) { 38 onReplyFunction.call(this); 39 } 40 }; 41 xhttp.open(method, url, true); 42 xhttp.send(); 43 44} 45 46
normalize.css
css
Responsive CSS to support web page. For ESP place in "sketchFolder\data" for upload via SPIFFS
1/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 3/** 4 5 * 1. Set default font family to sans-serif. 6 * 2. Prevent iOS text size adjust 7 after orientation change, without disabling 8 * user zoom. 9 */ 10 11html 12 { 13 font-family: sans-serif; /* 1 */ 14 -ms-text-size-adjust: 100%; /* 2 */ 15 16 -webkit-text-size-adjust: 100%; /* 2 */ 17} 18 19/** 20 * Remove default margin. 21 22 */ 23 24body { 25 margin: 0; 26} 27 28/* HTML5 display definitions 29 ========================================================================== 30 */ 31 32/** 33 * Correct `block` display not defined for any HTML5 element in 34 IE 8/9. 35 * Correct `block` display not defined for `details` or `summary` in 36 IE 10/11 37 * and Firefox. 38 * Correct `block` display not defined for `main` 39 in IE 11. 40 */ 41 42article, 43aside, 44details, 45figcaption, 46figure, 47footer, 48header, 49hgroup, 50main, 51menu, 52nav, 53section, 54summary 55 { 56 display: block; 57} 58 59/** 60 * 1. Correct `inline-block` display not 61 defined in IE 8/9. 62 * 2. Normalize vertical alignment of `progress` in Chrome, 63 Firefox, and Opera. 64 */ 65 66audio, 67canvas, 68progress, 69video { 70 71 display: inline-block; /* 1 */ 72 vertical-align: baseline; /* 2 */ 73} 74 75/** 76 77 * Prevent modern browsers from displaying `audio` without controls. 78 * Remove 79 excess height in iOS 5 devices. 80 */ 81 82audio:not([controls]) { 83 display: 84 none; 85 height: 0; 86} 87 88/** 89 * Address `[hidden]` styling not present 90 in IE 8/9/10. 91 * Hide the `template` element in IE 8/9/11, Safari, and Firefox 92 < 22. 93 */ 94 95[hidden], 96template { 97 display: none; 98} 99 100/* Links 101 102 ========================================================================== */ 103 104/** 105 106 * Remove the gray background color from active links in IE 10. 107 */ 108 109a { 110 111 background-color: transparent; 112} 113 114/** 115 * Improve readability when 116 focused and also mouse hovered in all browsers. 117 */ 118 119a:active, 120a:hover 121 { 122 outline: 0; 123} 124 125/* Text-level semantics 126 ========================================================================== 127 */ 128 129/** 130 * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 131 132 */ 133 134abbr[title] { 135 border-bottom: 1px dotted; 136} 137 138/** 139 * Address 140 style set to `bolder` in Firefox 4+, Safari, and Chrome. 141 */ 142 143b, 144strong 145 { 146 font-weight: bold; 147} 148 149/** 150 * Address styling not present in Safari 151 and Chrome. 152 */ 153 154dfn { 155 font-style: italic; 156} 157 158/** 159 * Address 160 variable `h1` font-size and margin within `section` and `article` 161 * contexts 162 in Firefox 4+, Safari, and Chrome. 163 */ 164 165h1 { 166 font-size: 2em; 167 margin: 168 0.67em 0; 169} 170 171/** 172 * Address styling not present in IE 8/9. 173 */ 174 175mark 176 { 177 background: #ff0; 178 color: #000; 179} 180 181/** 182 * Address inconsistent 183 and variable font size in all browsers. 184 */ 185 186small { 187 font-size: 80%; 188} 189 190/** 191 192 * Prevent `sub` and `sup` affecting `line-height` in all browsers. 193 */ 194 195sub, 196sup 197 { 198 font-size: 75%; 199 line-height: 0; 200 position: relative; 201 vertical-align: 202 baseline; 203} 204 205sup { 206 top: -0.5em; 207} 208 209sub { 210 bottom: -0.25em; 211} 212 213/* 214 Embedded content 215 ========================================================================== 216 */ 217 218/** 219 * Remove border when inside `a` element in IE 8/9/10. 220 */ 221 222img 223 { 224 border: 0; 225} 226 227/** 228 * Correct overflow not hidden in IE 9/10/11. 229 230 */ 231 232svg:not(:root) { 233 overflow: hidden; 234} 235 236/* Grouping content 237 238 ========================================================================== */ 239 240/** 241 242 * Address margin not present in IE 8/9 and Safari. 243 */ 244 245figure { 246 margin: 247 1em 40px; 248} 249 250/** 251 * Address differences between Firefox and other browsers. 252 253 */ 254 255hr { 256 -moz-box-sizing: content-box; 257 box-sizing: content-box; 258 259 height: 0; 260} 261 262/** 263 * Contain overflow in all browsers. 264 */ 265 266pre 267 { 268 overflow: auto; 269} 270 271/** 272 * Address odd `em`-unit font size rendering 273 in all browsers. 274 */ 275 276code, 277kbd, 278pre, 279samp { 280 font-family: 281 monospace, monospace; 282 font-size: 1em; 283} 284 285/* Forms 286 ========================================================================== 287 */ 288 289/** 290 * Known limitation: by default, Chrome and Safari on OS X allow 291 very limited 292 * styling of `select`, unless a `border` property is set. 293 */ 294 295/** 296 297 * 1. Correct color not being inherited. 298 * Known issue: affects color of disabled 299 elements. 300 * 2. Correct font properties not being inherited. 301 * 3. Address 302 margins set differently in Firefox 4+, Safari, and Chrome. 303 */ 304 305button, 306input, 307optgroup, 308select, 309textarea 310 { 311 color: inherit; /* 1 */ 312 font: inherit; /* 2 */ 313 margin: 0; /* 3 314 */ 315} 316 317/** 318 * Address `overflow` set to `hidden` in IE 8/9/10/11. 319 320 */ 321 322button { 323 overflow: visible; 324} 325 326/** 327 * Address inconsistent 328 `text-transform` inheritance for `button` and `select`. 329 * All other form control 330 elements do not inherit `text-transform` values. 331 * Correct `button` style inheritance 332 in Firefox, IE 8/9/10/11, and Opera. 333 * Correct `select` style inheritance in 334 Firefox. 335 */ 336 337button, 338select { 339 text-transform: none; 340} 341 342/** 343 344 * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 345 346 * and `video` controls. 347 * 2. Correct inability to style clickable `input` 348 types in iOS. 349 * 3. Improve usability and consistency of cursor style between 350 image-type 351 * `input` and others. 352 */ 353 354button, 355html input[type="button"], 356 /* 1 */ 357input[type="reset"], 358input[type="submit"] { 359 -webkit-appearance: 360 button; /* 2 */ 361 cursor: pointer; /* 3 */ 362} 363 364/** 365 * Re-set default 366 cursor for disabled elements. 367 */ 368 369button[disabled], 370html input[disabled] 371 { 372 cursor: default; 373} 374 375/** 376 * Remove inner padding and border in 377 Firefox 4+. 378 */ 379 380button::-moz-focus-inner, 381input::-moz-focus-inner { 382 383 border: 0; 384 padding: 0; 385} 386 387/** 388 * Address Firefox 4+ setting `line-height` 389 on `input` using `!important` in 390 * the UA stylesheet. 391 */ 392 393input { 394 395 line-height: normal; 396} 397 398/** 399 * It's recommended that you don't attempt 400 to style these elements. 401 * Firefox's implementation doesn't respect box-sizing, 402 padding, or width. 403 * 404 * 1. Address box sizing set to `content-box` in IE 405 8/9/10. 406 * 2. Remove excess padding in IE 8/9/10. 407 */ 408 409input[type="checkbox"], 410input[type="radio"] 411 { 412 box-sizing: border-box; /* 1 */ 413 padding: 0; /* 2 */ 414} 415 416/** 417 418 * Fix the cursor style for Chrome's increment/decrement buttons. For certain 419 420 * `font-size` values of the `input`, it causes the cursor style of the 421 * decrement 422 button to change from `default` to `text`. 423 */ 424 425input[type="number"]::-webkit-inner-spin-button, 426input[type="number"]::-webkit-outer-spin-button 427 { 428 height: auto; 429} 430 431/** 432 * 1. Address `appearance` set to `searchfield` 433 in Safari and Chrome. 434 * 2. Address `box-sizing` set to `border-box` in Safari 435 and Chrome 436 * (include `-moz` to future-proof). 437 */ 438 439input[type="search"] 440 { 441 -webkit-appearance: textfield; /* 1 */ 442 -moz-box-sizing: content-box; 443 444 -webkit-box-sizing: content-box; /* 2 */ 445 box-sizing: content-box; 446} 447 448/** 449 450 * Remove inner padding and search cancel button in Safari and Chrome on OS X. 451 452 * Safari (but not Chrome) clips the cancel button when the search input has 453 454 * padding (and `textfield` appearance). 455 */ 456 457input[type="search"]::-webkit-search-cancel-button, 458input[type="search"]::-webkit-search-decoration 459 { 460 -webkit-appearance: none; 461} 462 463/** 464 * Define consistent border, 465 margin, and padding. 466 */ 467 468fieldset { 469 border: 1px solid #c0c0c0; 470 471 margin: 0 2px; 472 padding: 0.35em 0.625em 0.75em; 473} 474 475/** 476 * 1. Correct 477 `color` not being inherited in IE 8/9/10/11. 478 * 2. Remove padding so people aren't 479 caught out if they zero out fieldsets. 480 */ 481 482legend { 483 border: 0; /* 484 1 */ 485 padding: 0; /* 2 */ 486} 487 488/** 489 * Remove default vertical scrollbar 490 in IE 8/9/10/11. 491 */ 492 493textarea { 494 overflow: auto; 495} 496 497/** 498 499 * Don't inherit the `font-weight` (applied by a rule above). 500 * NOTE: the default 501 cannot safely be changed in Chrome and Safari on OS X. 502 */ 503 504optgroup { 505 506 font-weight: bold; 507} 508 509/* Tables 510 ========================================================================== 511 */ 512 513/** 514 * Remove most spacing between table cells. 515 */ 516 517table 518 { 519 border-collapse: collapse; 520 border-spacing: 0; 521} 522 523td, 524th 525 { 526 padding: 0; 527}
ClientSideScript.js
javascript
Client JS to support web page. For ESP place in "sketchFolder\data" for upload via SPIFFS
1// Everything in pure JS to save codespace for your preferred Libs 2window.addEventListener("load", 3 onWindowLoad); 4 5// This all kicks in when the page lands on the client browser 6function 7 onWindowLoad() { 8 console.log("Page Loaded"); 9 // Add some Listeners 10 to our buttons to send requests back 11 document.getElementById("on").addEventListener("click", 12 sendOnRequest); 13 document.getElementById("off").addEventListener("click", 14 sendOffRequest); 15} 16 17function sendOnRequest() { 18 sendAjaxRequest( 19 20 function () { 21 document.getElementById("infoPanel").innerHTML 22 = this.responseText; 23 } 24 , "GET" 25 , "/socket/1/1/1" 26 27 ); 28} 29 30function sendOffRequest() { 31 sendAjaxRequest( 32 function 33 () { 34 document.getElementById("infoPanel").innerHTML = this.responseText; 35 36 } 37 , "GET" 38 , "/socket/1/1/0" 39 ); 40} 41 42// 43 Generic wrapper to send requests to the server 44function sendAjaxRequest(onReplyFunction, 45 method, url) { 46 var xhttp = new XMLHttpRequest() 47 // What happens when 48 the server replies with an answer 49 xhttp.onreadystatechange = function () 50 { 51 if (this.readyState == 4 && this.status == 200) { 52 onReplyFunction.call(this); 53 54 } 55 }; 56 xhttp.open(method, url, true); 57 xhttp.send(); 58 59} 60 61
Arduino Example Software for ESP32/ESP8266
arduino
Example software which is triggered by Google Assistant and turns on / off a power socket. Also has web UI which allows for web page control of the socket as well. Change headers if using a different board
1/* 2 Name: ESP32_WebServerApp_Example.ino 3 Created: 3/14/2019 12:06:43 AM 4 Author: Simon 5 6 Simple WebApp on SPIFFS Served Locally via mDNS Name or IP 7 Example #1 - RF Lightswitches - ESP32 as WiFi Client, Simple AJAX Requests or whole page loads for now (no WS yet) 8 9 Upload and go to http://esp32.local (or inspect Serial monitor if connecting via IP) 10 11 */ 12#ifdef ESP32 13 #include <spiffs.h> 14 #include <WiFi.h> 15 #include <ESPmDNS.h> 16 #define FORMAT_SPIFFS_IF_FAILED false // You may have to set this to true the first time you run this 17#endif 18 19#ifdef ESP8266 20 #include <FS.h> 21 #include <ESP8266WiFi.h> 22 #include <ESP8266mDNS.h> 23 #define FORMAT_SPIFFS_IF_FAILED // Leave Empty on ESP8266 24#endif 25 26#include <RCSwitch.h> 27 28// WiFi Client Settings 29const char* ssid = "**************"; 30const char* password = "**************"; 31const char* mDnsName = "esp32"; 32const byte hwPin_rfTx = 2; 33 34WiFiServer server(9090); 35RCSwitch mySwitch = RCSwitch(); 36File root; 37void setup() { 38 Serial.begin(115200); 39 delay(5000); 40 // Setup our File System in SPIFFS 41 if (!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)) { 42 Serial.println("SPIFFS Mount Failed"); 43 return; 44 } 45 root = SPIFFS.open("/", "r"); 46 47 // Static IP Configuration 48 IPAddress local_IP(192, 168, 0, 55); 49 IPAddress gateway(192, 168, 0, 1); 50 IPAddress subnet(255, 255, 255, 0); 51 IPAddress primaryDNS(192, 168, 0, 1); 52 IPAddress secondaryDNS(8, 8, 4, 4); // fake 53 54 WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS); 55 56 // Setup the Web Connection 57 WiFi.begin(ssid, password); 58 59 Serial.println(F("Connecting to Wifi. ")); 60 while (!WL_CONNECTED || WiFi.localIP().toString() == "0.0.0.0") { 61 delay(500); // Yield() sdasdasdasd 62 Serial.print(". "); 63 } 64 65 // Setup our Remote Controlled Wall Socket 66 mySwitch.enableTransmit(2); 67 Serial.print("Connected to "); 68 Serial.print(ssid); 69 Serial.print(" on IP address: "); 70 Serial.println(WiFi.localIP()); 71 72 // Set up mDNS responder: 73 // - first argument is the domain name, in this example 74 // the fully-qualified domain name is "mDnsName.local" 75 if (!MDNS.begin(mDnsName)) { 76 Serial.println("Error setting up MDNS responder!"); 77 } 78 else { 79 Serial.println("mDNS responder started"); 80 } 81 82 // Finally startup the web server 83 server.begin(); 84 Serial.println("TCP server started."); 85 86 // Bind the HTTP requests via MDNS 87 MDNS.addService("http", "tcp", 9090); 88} 89 90 91void loop(void) { 92 WiFiClient client = server.available(); // listen for incoming clients 93 94 if (client) { // Someone is talking to us... 95 96 97 String currentLine = ""; // make a String to hold incoming data from the client 98 while (client.connected()) { // loop while the client's connected 99 100 String req = client.readStringUntil('\r'); // Read the first line of HTTP request 101 102 // First line of HTTP request looks like "GET /path HTTP/1.1" 103 // Retrieve the "/path" part by finding the spaces 104 int addr_start = req.indexOf(' '); 105 int addr_end = req.indexOf(' ', addr_start + 1); 106 if (addr_start == -1 || addr_end == -1) { 107 Serial.print("Invalid request: "); 108 Serial.println(req); 109 break; 110 } 111 req = req.substring(addr_start + 1, addr_end); 112 Serial.print("Request: "); 113 Serial.println(req); 114 115 // Set Access Control Policy to allow CORS (Not actually needed here at present...) 116 client.println("HTTP/1.1 200 OK\ \ 117Access-Control-Allow-Origin: *\ \ 118Content-Type: text/html\ \ 119\ \ 120"); 121 handleFileRead(req, client); 122 } 123 124 // close the connection: 125 client.stop(); 126 Serial.println("Client Disconnected."); 127 } 128} 129 130// Handle all the content types we may get asked for from our SPIFFS 131String getContentType(String filename) { 132 if (filename.endsWith(".htm")) return "text/html"; 133 else if (filename.endsWith(".html")) return "text/html"; 134 else if (filename.endsWith(".css")) return "text/css"; 135 else if (filename.endsWith(".js")) return "application/javascript"; 136 else if (filename.endsWith(".png")) return "image/png"; 137 else if (filename.endsWith(".gif")) return "image/gif"; 138 else if (filename.endsWith(".jpg")) return "image/jpeg"; 139 else if (filename.endsWith(".ico")) return "image/x-icon"; 140 else if (filename.endsWith(".xml")) return "text/xml"; 141 return "text/plain"; 142} 143 144// Handle a File request either via our custom handlers, or simply serving a file... 145bool handleFileRead(String path, WiFiClient &client) { 146 Serial.println("handleFileRead: " + path); 147 if (path.endsWith("/")) path += "index.html"; // If a folder is requested, send the index file 148 String contentType = getContentType(path); // Get the MIME type 149 150 // Simple hardcoding for now but can easily be expanded into the below 151 // If we used a command with a number it would map in but "turn the light 1" sounds odd.. 152 if (path.startsWith("/on")) { 153 mySwitch.switchOn(1, 1); 154 } 155 else if (path.startsWith("/off")) { 156 mySwitch.switchOff(1, 1); 157 } 158 else 159 // Handle our "custom" (non-file) requests first 160 // We Expect the URL in format /socket/1/1/1 meaning:Socket 1, Address 1, Action ON 161 if (path.startsWith("/socket/")) { 162 int socket = path.charAt(8) - 48; 163 int address = path.charAt(10) - 48; 164 int action = path.charAt(12) - 48; 165 166 client.print("Socket "); 167 client.print(socket); 168 client.print(":"); 169 client.print(address); 170 171 if (action == 1) { 172 mySwitch.switchOn(socket, address); 173 client.println(" ON"); 174 return true; 175 } 176 else { 177 mySwitch.switchOff(socket, address); 178 client.println(" OFF"); 179 return true; 180 } 181 } 182 else if (SPIFFS.exists(path)) { // If the file exists 183 File file = SPIFFS.open(path, "r"); // Open it 184 client.print(file.readStringUntil(EOF)); // Read Until End Of File back to client 185 file.close(); // Then close the file again 186 return true; 187 } 188 189 Serial.println("\ File Not Found"); 190 client.print("<b>Invalid Request</b>"); // Show the user some info on web page 191 return false; // If the file doesn't exist, return false 192} 193
data\Index.html
html
Web Page for data partition of ESP board (or PROGMEM / Webserver). For ESP place in "sketchFolder\data" for upload via SPIFFS Uses simple responsive framework (included in other files)
1<HTML> 2<HEAD> 3 <!-- Basic Page Needs --> 4 <meta charset="utf-8"> 5 <title>ESP Web App</title> 6 <meta name="description" content="Starting you Off with IoT"> 7 <meta name="author" content="vMicro"> 8 9 <!-- Mobile Specific Metas --> 10 <meta name="viewport" content="width=device-width, initial-scale=1; maximum-scale=5.0; user-scalable=0;"> 11 <meta name="apple-mobile-web-app-capable" content="yes" /> 12 13 <!-- CSS --> 14 <link rel="stylesheet" href="normalize.css"> 15 <link rel="stylesheet" href="skeleton.css"> 16 17 <!-- Client Scripts --> 18 <script type="text/javascript" src="/ClientSideScript.js"></script> 19</HEAD> 20<BODY> 21 22 <div class="container"> 23 <div class="row"> 24 <h2>Embedded SPIFFS ESP Application (8266/8285/32)</h2> 25 <p>About as simple as it can be made, and all simplistic, easy to edit code.....</p> 26 </div> 27 <div class="row"> 28 <button id="on" class="button-primary">1-1 On</button> 29 <button id="off">1-1 Off</button> 30 </div> 31 <div class="row"> 32 <div>Response: <span id="infoPanel"></span></div> 33 </div> 34 </div> 35</BODY> 36 37 38</HTML> 39
skeleton.css
css
Responsive CSS to support web page. For ESP place in "sketchFolder\data" for upload via SPIFFS
1/* 2* Skeleton V2.0.4 3* Copyright 2014, Dave Gamache 4* www.getskeleton.com 5* Free to use under the MIT license. 6* http://www.opensource.org/licenses/mit-license.php 7* 12/29/2014 8*/ 9 10 11/* Table of contents 12 13- Grid 14- Base Styles 15- Typography 16- Links 17- Buttons 18- Forms 19- Lists 20- Code 21- Tables 22- Spacing 23- Utilities 24- Clearing 25- Media Queries 26*/ 27 28 29/* Grid 30 */ 31.container { 32 position: relative; 33 width: 100%; 34 max-width: 960px; 35 margin: 0 auto; 36 padding: 0 20px; 37 box-sizing: border-box; } 38.column, 39.columns { 40 width: 100%; 41 float: left; 42 box-sizing: border-box; } 43 44/* For devices larger than 400px */ 45@media (min-width: 400px) { 46 .container { 47 width: 85%; 48 padding: 0; } 49} 50 51/* For devices larger than 550px */ 52/* HACKED To ensure it remains the same on mobile */ 53@media (min-width: 320px) { 54 .container { 55 width: 80%; } 56 .column, 57 .columns { 58 margin-left: 4%; } 59 .column:first-child, 60 .columns:first-child { 61 margin-left: 0; } 62 63 .one.column, 64 .one.columns { width: 4.66666666667%; } 65 .two.columns { width: 13.3333333333%; } 66 .three.columns { width: 22%; } 67 .four.columns { width: 30.6666666667%; } 68 .five.columns { width: 39.3333333333%; } 69 .six.columns { width: 48%; } 70 .seven.columns { width: 56.6666666667%; } 71 .eight.columns { width: 65.3333333333%; } 72 .nine.columns { width: 74.0%; } 73 .ten.columns { width: 82.6666666667%; } 74 .eleven.columns { width: 91.3333333333%; } 75 .twelve.columns { width: 100%; margin-left: 0; } 76 77 .one-third.column { width: 30.6666666667%; } 78 .two-thirds.column { width: 65.3333333333%; } 79 80 .one-half.column { width: 48%; } 81 82 /* Offsets */ 83 .offset-by-one.column, 84 .offset-by-one.columns { margin-left: 8.66666666667%; } 85 .offset-by-two.column, 86 .offset-by-two.columns { margin-left: 17.3333333333%; } 87 .offset-by-three.column, 88 .offset-by-three.columns { margin-left: 26%; } 89 .offset-by-four.column, 90 .offset-by-four.columns { margin-left: 34.6666666667%; } 91 .offset-by-five.column, 92 .offset-by-five.columns { margin-left: 43.3333333333%; } 93 .offset-by-six.column, 94 .offset-by-six.columns { margin-left: 52%; } 95 .offset-by-seven.column, 96 .offset-by-seven.columns { margin-left: 60.6666666667%; } 97 .offset-by-eight.column, 98 .offset-by-eight.columns { margin-left: 69.3333333333%; } 99 .offset-by-nine.column, 100 .offset-by-nine.columns { margin-left: 78.0%; } 101 .offset-by-ten.column, 102 .offset-by-ten.columns { margin-left: 86.6666666667%; } 103 .offset-by-eleven.column, 104 .offset-by-eleven.columns { margin-left: 95.3333333333%; } 105 106 .offset-by-one-third.column, 107 .offset-by-one-third.columns { margin-left: 34.6666666667%; } 108 .offset-by-two-thirds.column, 109 .offset-by-two-thirds.columns { margin-left: 69.3333333333%; } 110 111 .offset-by-one-half.column, 112 .offset-by-one-half.columns { margin-left: 52%; } 113 114} 115 116 117/* Base Styles 118 */ 119/* NOTE 120html is set to 62.5% so that all the REM measurements throughout Skeleton 121are based on 10px sizing. So basically 1.5rem = 15px :) */ 122html { 123 font-size: 62.5%; } 124body { 125 font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */ 126 line-height: 1.6; 127 font-weight: 400; 128 font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; 129 color: #222; } 130 131 132/* Typography 133 */ 134h1, h2, h3, h4, h5, h6 { 135 margin-top: 0; 136 margin-bottom: 2rem; 137 font-weight: 300; } 138h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;} 139h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; } 140h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; } 141h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; } 142h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; } 143h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; } 144 145/* Larger than phablet */ 146@media (min-width: 550px) { 147 h1 { font-size: 5.0rem; } 148 h2 { font-size: 4.2rem; } 149 h3 { font-size: 3.6rem; } 150 h4 { font-size: 3.0rem; } 151 h5 { font-size: 2.4rem; } 152 h6 { font-size: 1.5rem; } 153} 154 155p { 156 margin-top: 0; } 157 158 159/* Links 160 */ 161a { 162 color: #1EAEDB; } 163a:hover { 164 color: #0FA0CE; } 165 166 167/* Buttons 168 */ 169.button, 170button, 171input[type="submit"], 172input[type="reset"], 173input[type="button"] { 174 display: inline-block; 175 height: 38px; 176 padding: 0 30px; 177 color: #555; 178 text-align: center; 179 font-size: 11px; 180 font-weight: 600; 181 line-height: 38px; 182 letter-spacing: .1rem; 183 text-transform: uppercase; 184 text-decoration: none; 185 white-space: nowrap; 186 background-color: transparent; 187 border-radius: 4px; 188 border: 1px solid #bbb; 189 cursor: pointer; 190 box-sizing: border-box; } 191.button:hover, 192button:hover, 193input[type="submit"]:hover, 194input[type="reset"]:hover, 195input[type="button"]:hover, 196.button:focus, 197button:focus, 198input[type="submit"]:focus, 199input[type="reset"]:focus, 200input[type="button"]:focus { 201 color: #333; 202 border-color: #888; 203 outline: 0; } 204.button.button-primary, 205button.button-primary, 206input[type="submit"].button-primary, 207input[type="reset"].button-primary, 208input[type="button"].button-primary { 209 color: #FFF; 210 background-color: #33C3F0; 211 border-color: #33C3F0; } 212.button.button-primary:hover, 213button.button-primary:hover, 214input[type="submit"].button-primary:hover, 215input[type="reset"].button-primary:hover, 216input[type="button"].button-primary:hover, 217.button.button-primary:focus, 218button.button-primary:focus, 219input[type="submit"].button-primary:focus, 220input[type="reset"].button-primary:focus, 221input[type="button"].button-primary:focus { 222 color: #FFF; 223 background-color: #1EAEDB; 224 border-color: #1EAEDB; } 225 226 227/* Forms 228 */ 229input[type="email"], 230input[type="number"], 231input[type="search"], 232input[type="text"], 233input[type="tel"], 234input[type="url"], 235input[type="password"], 236textarea, 237select { 238 height: 38px; 239 padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */ 240 background-color: #fff; 241 border: 1px solid #D1D1D1; 242 border-radius: 4px; 243 box-shadow: none; 244 box-sizing: border-box; } 245/* Removes awkward default styles on some inputs for iOS */ 246input[type="email"], 247input[type="number"], 248input[type="search"], 249input[type="text"], 250input[type="tel"], 251input[type="url"], 252input[type="password"], 253textarea { 254 -webkit-appearance: none; 255 -moz-appearance: none; 256 appearance: none; } 257textarea { 258 min-height: 65px; 259 padding-top: 6px; 260 padding-bottom: 6px; } 261input[type="email"]:focus, 262input[type="number"]:focus, 263input[type="search"]:focus, 264input[type="text"]:focus, 265input[type="tel"]:focus, 266input[type="url"]:focus, 267input[type="password"]:focus, 268textarea:focus, 269select:focus { 270 border: 1px solid #33C3F0; 271 outline: 0; } 272label, 273legend { 274 display: block; 275 margin-bottom: .5rem; 276 font-weight: 600; } 277fieldset { 278 padding: 0; 279 border-width: 0; } 280input[type="checkbox"], 281input[type="radio"] { 282 display: inline; } 283label > .label-body { 284 display: inline-block; 285 margin-left: .5rem; 286 font-weight: normal; } 287 288 289/* Lists 290 */ 291ul { 292 list-style: circle inside; } 293ol { 294 list-style: decimal inside; } 295ol, ul { 296 padding-left: 0; 297 margin-top: 0; } 298ul ul, 299ul ol, 300ol ol, 301ol ul { 302 margin: 1.5rem 0 1.5rem 3rem; 303 font-size: 90%; } 304li { 305 margin-bottom: 1rem; } 306 307 308/* Code 309 */ 310code { 311 padding: .2rem .5rem; 312 margin: 0 .2rem; 313 font-size: 90%; 314 white-space: nowrap; 315 background: #F1F1F1; 316 border: 1px solid #E1E1E1; 317 border-radius: 4px; } 318pre > code { 319 display: block; 320 padding: 1rem 1.5rem; 321 white-space: pre; } 322 323 324/* Tables 325 */ 326th, 327td { 328 padding: 12px 15px; 329 text-align: left; 330 border-bottom: 1px solid #E1E1E1; } 331th:first-child, 332td:first-child { 333 padding-left: 0; } 334th:last-child, 335td:last-child { 336 padding-right: 0; } 337 338 339/* Spacing 340 */ 341button, 342.button { 343 margin-bottom: 1rem; } 344input, 345textarea, 346select, 347fieldset { 348 margin-bottom: 1.5rem; } 349pre, 350blockquote, 351dl, 352figure, 353table, 354p, 355ul, 356ol, 357form { 358 margin-bottom: 2.5rem; } 359 360 361/* Utilities 362 */ 363.u-full-width { 364 width: 100%; 365 box-sizing: border-box; } 366.u-max-full-width { 367 max-width: 100%; 368 box-sizing: border-box; } 369.u-pull-right { 370 float: right; } 371.u-pull-left { 372 float: left; } 373 374 375/* Misc 376 */ 377hr { 378 margin-top: 3rem; 379 margin-bottom: 3.5rem; 380 border-width: 0; 381 border-top: 1px solid #E1E1E1; } 382 383 384/* Clearing 385 */ 386 387/* Self Clearing Goodness */ 388.container:after, 389.row:after, 390.u-cf { 391 content: ""; 392 display: table; 393 clear: both; } 394 395 396/* Media Queries 397 */ 398/* 399Note: The best way to structure the use of media queries is to create the queries 400near the relevant code. For example, if you wanted to change the styles for buttons 401on small devices, paste the mobile query code up in the buttons section and style it 402there. 403*/ 404 405 406/* Larger than mobile */ 407@media (min-width: 400px) {} 408 409/* Larger than phablet (also point when grid becomes active) */ 410@media (min-width: 550px) {} 411 412/* Larger than tablet */ 413@media (min-width: 750px) {} 414 415/* Larger than desktop */ 416@media (min-width: 1000px) {} 417 418/* Larger than Desktop HD */ 419@media (min-width: 1200px) {} 420
Downloadable files
ESP Power Plug Wiring Example
An Example of wiring an RF Transmitter to an ESP32 to allow a set of RF Power sockets to be controlled from the Arduino platform.
ESP Power Plug Wiring Example

Comments
Only logged in users can leave comments