New Combo ESP8266 + Arduino Pro Mini via i2c
This commit is contained in:
5
HCPBridgeCombo/ESP/.gitignore
vendored
Normal file
5
HCPBridgeCombo/ESP/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
7
HCPBridgeCombo/ESP/.vscode/extensions.json
vendored
Normal file
7
HCPBridgeCombo/ESP/.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
39
HCPBridgeCombo/ESP/include/README
Normal file
39
HCPBridgeCombo/ESP/include/README
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
46
HCPBridgeCombo/ESP/lib/README
Normal file
46
HCPBridgeCombo/ESP/lib/README
Normal file
@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
19
HCPBridgeCombo/ESP/platformio.ini
Normal file
19
HCPBridgeCombo/ESP/platformio.ini
Normal file
@ -0,0 +1,19 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:esp12e]
|
||||
platform = espressif8266
|
||||
board = esp12e
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
ottowinter/ESPAsyncWebServer-esphome@^1.2.7
|
||||
bblanchon/ArduinoJson@^6.17.2
|
||||
ayushsharma82/AsyncElegantOTA@^2.2.5
|
||||
krzychb/EspSaveCrash@^1.2.0
|
1
HCPBridgeCombo/ESP/src/index_html.h
Normal file
1
HCPBridgeCombo/ESP/src/index_html.h
Normal file
File diff suppressed because one or more lines are too long
180
HCPBridgeCombo/ESP/src/main.cpp
Normal file
180
HCPBridgeCombo/ESP/src/main.cpp
Normal file
@ -0,0 +1,180 @@
|
||||
#include <Arduino.h>
|
||||
#include "EspSaveCrash.h"
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <AsyncElegantOTA.h>
|
||||
#include <AsyncJson.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <Wire.h>
|
||||
#include "index_html.h"
|
||||
#include "../../Arduino/src/i2cshare.h"
|
||||
|
||||
|
||||
/* create this file and add your wlan credentials
|
||||
const char* ssid = "MyWLANSID";
|
||||
const char* password = "MYPASSWORD";
|
||||
*/
|
||||
#include "../../../../private/credentials.h"
|
||||
|
||||
|
||||
// switch relay sync to the lamp
|
||||
// e.g. the Wifi Relay Board U4648
|
||||
#define USERELAY
|
||||
|
||||
|
||||
// Relay Board parameters
|
||||
#define ESP8266_GPIO2 2 // Blue LED.
|
||||
#define ESP8266_GPIO4 4 // Relay control.
|
||||
#define ESP8266_GPIO5 5 // Optocoupler input.
|
||||
#define LED_PIN ESP8266_GPIO2
|
||||
|
||||
EspSaveCrash SaveCrash;
|
||||
// the buffer to put the Crash log to
|
||||
char *_debugOutputBuffer;
|
||||
|
||||
|
||||
SHCIState lastState;
|
||||
|
||||
// webserver on port 80
|
||||
AsyncWebServer server(80);
|
||||
|
||||
unsigned long nextStateCall = millis();
|
||||
unsigned long lasti2cmsgtime = millis();
|
||||
|
||||
|
||||
// switch GPIO4 und GPIO2 sync to the lamp
|
||||
void onStatusChanged(){
|
||||
//see https://ucexperiment.wordpress.com/2016/12/18/yunshan-esp8266-250v-15a-acdc-network-wifi-relay-module/
|
||||
//Setting GPIO4 high, causes the relay to close the NO contact with
|
||||
#ifdef USERELAY
|
||||
bool lamp = lastState.valid && lastState.lampOn;
|
||||
digitalWrite( ESP8266_GPIO4, lamp );
|
||||
digitalWrite(LED_PIN, lamp);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// setup mcu
|
||||
void setup(){
|
||||
|
||||
lastState.valid = false;
|
||||
lastState.reserved = 0xAB;
|
||||
|
||||
// Setup I2C Master on UART Pins to use relayboard
|
||||
//ESP 8266 PIN 1(TX0) and PIN 3 (RX0)
|
||||
Wire.begin(1,3);
|
||||
|
||||
_debugOutputBuffer = (char *) calloc(2048, sizeof(char));
|
||||
|
||||
//setup wifi
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid, password);
|
||||
WiFi.setAutoReconnect(true);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// setup http server
|
||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
AsyncWebServerResponse *response = request->beginResponse_P( 200, "text/html", index_html,sizeof(index_html));
|
||||
response->addHeader("Content-Encoding","deflate");
|
||||
request->send(response);
|
||||
});
|
||||
|
||||
server.on("/status", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
|
||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||
DynamicJsonDocument root(1024);
|
||||
root["valid"] = lastState.valid;
|
||||
root["doorstate"] = lastState.doorState;
|
||||
root["doorposition"] = lastState.doorCurrentPosition;
|
||||
root["doortarget"] = lastState.doorTargetPosition;
|
||||
root["lamp"] = lastState.lampOn;
|
||||
root["debug"] = lastState.reserved;
|
||||
root["cc"] = lastState.cc;
|
||||
root["lastresponse"] = millis()-lasti2cmsgtime;
|
||||
|
||||
serializeJson(root,*response);
|
||||
request->send(response);
|
||||
});
|
||||
|
||||
server.on("/command", HTTP_GET, [] (AsyncWebServerRequest *request) {
|
||||
if (request->hasParam("action")) {
|
||||
int actionid = request->getParam("action")->value().toInt();
|
||||
switch (actionid){
|
||||
case I2C_CMD_CLOSEDOOR:
|
||||
case I2C_CMD_OPENDOOR:
|
||||
case I2C_CMD_OPENDOORHALF:
|
||||
case I2C_CMD_STOPDOOR:
|
||||
case I2C_CMD_VENTPOS:
|
||||
case I2C_CMD_TOGGLELAMP:
|
||||
Wire.beginTransmission(I2CADDR);
|
||||
Wire.write((unsigned char)actionid);
|
||||
Wire.endTransmission();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
request->send(200, "text/plain", "OK");
|
||||
});
|
||||
|
||||
server.on("/crashinfo", HTTP_GET, [] (AsyncWebServerRequest *request){
|
||||
strcpy(_debugOutputBuffer, "");
|
||||
SaveCrash.print(_debugOutputBuffer,2048);
|
||||
if (request->hasParam("clear")) {
|
||||
SaveCrash.clear();
|
||||
}
|
||||
request->send(200, "text/plain", _debugOutputBuffer);
|
||||
});
|
||||
|
||||
server.on("/sysinfo", HTTP_GET, [] (AsyncWebServerRequest *request) {
|
||||
char buffer[150];
|
||||
rst_info* rinfo = ESP.getResetInfoPtr();
|
||||
|
||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||
DynamicJsonDocument root(1024);
|
||||
root["freemem"] = ESP.getFreeHeap();
|
||||
root["hostname"] = WiFi.hostname();
|
||||
root["ip"] = WiFi.localIP().toString();
|
||||
root["ssid"] = String(ssid);
|
||||
root["wifistatus"] = WiFi.status();
|
||||
root["resetreason"] =ESP.getResetReason();
|
||||
root["errors"] = rinfo->exccause;
|
||||
|
||||
//The address of the last crash is printed, which is used to
|
||||
sprintf(buffer, "epc1=0x%08x, epc2=0x%08x, epc3=0x%08x, excvaddr=0x%08x, depc=0x%08x, exccause=0x%x, reason=0x%x",
|
||||
rinfo->epc1, rinfo->epc2, rinfo->epc3, rinfo->excvaddr, rinfo->depc, rinfo->exccause, rinfo->reason);
|
||||
root["rstinfo"] = buffer;
|
||||
serializeJson(root,*response);
|
||||
|
||||
request->send(response);
|
||||
});
|
||||
|
||||
AsyncElegantOTA.begin(&server);
|
||||
server.begin();
|
||||
|
||||
//setup relay board
|
||||
#ifdef USERELAY
|
||||
pinMode( ESP8266_GPIO4, OUTPUT ); // Relay control pin.
|
||||
pinMode( ESP8266_GPIO5, INPUT_PULLUP ); // Input pin.
|
||||
pinMode( LED_PIN, OUTPUT ); // ESP8266 module blue L
|
||||
digitalWrite( ESP8266_GPIO4, 0 );
|
||||
digitalWrite(LED_PIN,0);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void loop(){
|
||||
if(nextStateCall < millis()){
|
||||
Wire.requestFrom(I2CADDR, sizeof(SHCIState));
|
||||
if(sizeof(SHCIState) != Wire.readBytes((unsigned char*) &lastState, sizeof(SHCIState))){
|
||||
lasti2cmsgtime = millis();
|
||||
onStatusChanged();
|
||||
}
|
||||
nextStateCall = millis()+200;
|
||||
}
|
||||
AsyncElegantOTA.loop();
|
||||
}
|
1
HCPBridgeCombo/ESP/src/webpage/buildindex.cmd
Normal file
1
HCPBridgeCombo/ESP/src/webpage/buildindex.cmd
Normal file
@ -0,0 +1 @@
|
||||
python compress.py
|
0
HCPBridgeCombo/ESP/src/webpage/command
Normal file
0
HCPBridgeCombo/ESP/src/webpage/command
Normal file
35
HCPBridgeCombo/ESP/src/webpage/compress.py
Normal file
35
HCPBridgeCombo/ESP/src/webpage/compress.py
Normal file
@ -0,0 +1,35 @@
|
||||
#pip install htmlmin
|
||||
#or python -m pip install htmlmin
|
||||
#pip install jsmin
|
||||
#or python -m pip install jsmin
|
||||
|
||||
import gzip
|
||||
import zlib
|
||||
import htmlmin
|
||||
from jsmin import jsmin
|
||||
|
||||
|
||||
|
||||
content = ""
|
||||
with open('index.html','rt',encoding="utf-8") as f:
|
||||
content=f.read()
|
||||
|
||||
|
||||
content = htmlmin.minify(content, remove_comments=True, remove_empty_space=True, remove_all_empty_space=True, reduce_empty_attributes=True, reduce_boolean_attributes=False, remove_optional_attribute_quotes=True, convert_charrefs=True, keep_pre=False)
|
||||
|
||||
|
||||
import re
|
||||
regex = r"<script>(.+?)<\/script>"
|
||||
content = re.sub(regex, lambda x: "<script>"+jsmin(x.group(1))+"</script>" ,content, 0, re.DOTALL)
|
||||
|
||||
result =""
|
||||
for c in zlib.compress(content.encode("UTF-8"),9):
|
||||
result= result + ("0x%02X" %c)
|
||||
if len(result)> 0:
|
||||
result=result + ","
|
||||
|
||||
|
||||
with open('../index_html.h',"wt") as f:
|
||||
f.write("const uint8_t index_html[] PROGMEM = {");
|
||||
f.write(result.strip(","))
|
||||
f.write("};");
|
159
HCPBridgeCombo/ESP/src/webpage/index.html
Normal file
159
HCPBridgeCombo/ESP/src/webpage/index.html
Normal file
@ -0,0 +1,159 @@
|
||||
<!DOCTYPE HTML><html>
|
||||
<head>
|
||||
<title>Garagentor Steuerung</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="data:,">
|
||||
<style>
|
||||
html {font-family: Arial; display: inline-block; text-align: center;}
|
||||
h2 {font-size: 3.0rem;}
|
||||
p {font-size: 3.0rem;}
|
||||
body {max-width: 600px; margin:0px auto; padding-bottom: 25px;}
|
||||
.switch {position: relative; display: inline-block; width: 80px; height: 48px}
|
||||
.switch input {display: none}
|
||||
.slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 6px}
|
||||
.slider:before {position: absolute; content: ""; height: 32px; width: 32px; left: 8px; bottom: 8px; background-color: #fff; -webkit-transition: .4s; transition: .4s; border-radius: 3px}
|
||||
input:checked+.slider {background-color: #b30000}
|
||||
input:checked+.slider:before {-webkit-transform: translateX(32px); -ms-transform: translateX(32px); transform: translateX(32px)}
|
||||
|
||||
.button {
|
||||
border: 4px;
|
||||
border-style: solid;
|
||||
color: black;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
text-align: center;
|
||||
display: inline;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
margin: 4px 2px;
|
||||
cursor: pointer;
|
||||
border-radius: 50px;
|
||||
}
|
||||
.buttonred {border-color: #ED5961;}
|
||||
.buttonyellow {border-color: #fcca00;}
|
||||
.buttongreen {border-color: #48bd81;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Garagentor</h2>
|
||||
<canvas width="250px" height="250px" id="dc"></canvas>
|
||||
<h3 id="status">warte auf Verbindung.</h3>
|
||||
|
||||
<hr/>
|
||||
<button class="button buttonred" onclick="doCommand(1)">Auf</button> <button class="button buttonyellow" onclick="doCommand(2)">Stop</button> <button class="button buttongreen" onclick="doCommand(0)">Zu</button>
|
||||
<hr/>
|
||||
<h4>Licht</h4><label class="switch"><input type="checkbox" onchange="doCommand(5)" id="light"><span class="slider"></span></label>
|
||||
<hr/>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
doorpos = 10;
|
||||
dir = -1;
|
||||
isconnected = false;
|
||||
var animation;
|
||||
function startDoorAnimation() {
|
||||
if(!animation){
|
||||
animation = setInterval(Draw, 200);
|
||||
}
|
||||
|
||||
}
|
||||
function stopDoorAnimation() {
|
||||
if(animation){
|
||||
clearInterval(animation);
|
||||
}
|
||||
animation = null;
|
||||
}
|
||||
|
||||
function Draw(){
|
||||
var svg =document.getElementById("svg");
|
||||
var dc = document.getElementById("dc");
|
||||
var ctx = dc.getContext("2d");
|
||||
width = dc.width;
|
||||
height = dc.height;
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
xa= [18,18,10,3,174,347,340,332,332,297,297,52,52,18];
|
||||
ya= [327,114,117,100,22,100,117,114,327,327,112,112,327,327];
|
||||
|
||||
ctx.fillStyle = "black";
|
||||
ctx.beginPath();
|
||||
for (i =0;i<xa.length;i++){
|
||||
if(i==0){
|
||||
ctx.moveTo((xa[i]/350) * width , (ya[i]/350)*width);
|
||||
}else{
|
||||
ctx.lineTo((xa[i]/350) * width, (ya[i]/350)*width);
|
||||
}
|
||||
}
|
||||
ctx.fill();
|
||||
|
||||
for(i=0;i<doorpos;i++){
|
||||
ctx.fillRect((62/350) * width, ((120+21*i)/350) * width, (225/350) * width, (18/350) * width);
|
||||
}
|
||||
doorpos+=dir;
|
||||
|
||||
if(dir<0 && doorpos<=0){
|
||||
dir=dir*-1;
|
||||
}
|
||||
if(dir>0 &&doorpos>=10){
|
||||
dir=dir*-1;
|
||||
}
|
||||
}
|
||||
|
||||
function doCommand(action) {
|
||||
if(!isconnected){return;}
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "/command?action="+action, true);
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
function setDoorState(state){
|
||||
stopDoorAnimation();
|
||||
if(state == 0) {doorpos = 10;dir = -1};
|
||||
if(state == 1) {doorpos = 0; dir = 1};
|
||||
if(state == 2) {doorpos = 5; dir = 1};
|
||||
Draw();
|
||||
if(state == 3) startDoorAnimation();
|
||||
}
|
||||
|
||||
function getStatusText(id){
|
||||
result = "Das Tor "
|
||||
switch(id)
|
||||
{
|
||||
case 0x20: setDoorState(1); return result+"ist geöffnet.";
|
||||
case 0x40: setDoorState(0); return result+"ist geschlossen.";
|
||||
case 0x80: setDoorState(2); return result+"ist teilgeöffnet.";
|
||||
case 0x00: setDoorState(2); return result+"ist teilgeöffnet.";
|
||||
case 0x02: setDoorState(3); return result+"schließt.";
|
||||
case 0x01: setDoorState(3); return result+"öffnet.";
|
||||
case -1: setDoorState(0); return "keine Verbindung zum Tor.";
|
||||
default: return "unbekanter Status: " + id;
|
||||
}
|
||||
}
|
||||
|
||||
function updateData(){
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
var status = JSON.parse(this.responseText);
|
||||
isconnected = status.valid;
|
||||
document.getElementById("status").innerHTML = getStatusText(status.valid?status.doorstate:-1);
|
||||
document.getElementById("light").checked = status.lamp & status.valid;
|
||||
return;
|
||||
}
|
||||
isconnected= false;
|
||||
};
|
||||
xmlhttp.open("GET", "/status", true);
|
||||
xmlhttp.send();
|
||||
}
|
||||
|
||||
Draw();
|
||||
updateData();
|
||||
setInterval(updateData, 3000);
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
1
HCPBridgeCombo/ESP/src/webpage/runtestserver.cmd
Normal file
1
HCPBridgeCombo/ESP/src/webpage/runtestserver.cmd
Normal file
@ -0,0 +1 @@
|
||||
python -m http.server
|
9
HCPBridgeCombo/ESP/src/webpage/status
Normal file
9
HCPBridgeCombo/ESP/src/webpage/status
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"valid" : true,
|
||||
"doorstate" : 1,
|
||||
"doorposition" : 0,
|
||||
"doortarget" : 0,
|
||||
"lamp" : true,
|
||||
"debug" : 0,
|
||||
"lastresponse" : 0
|
||||
}
|
11
HCPBridgeCombo/ESP/test/README
Normal file
11
HCPBridgeCombo/ESP/test/README
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
This directory is intended for PlatformIO Unit Testing and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/page/plus/unit-testing.html
|
Reference in New Issue
Block a user