├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── LICENSE ├── README.md ├── docs ├── MeshTopology.md └── images │ └── MeshTopology.png ├── examples ├── ESP8266MeshHelloWorld │ ├── README.md │ ├── data │ │ └── ssl │ │ │ ├── fingerprint │ │ │ ├── server.cer │ │ │ └── server.key │ ├── platformio.ini │ └── src │ │ ├── ESP8266MeshHelloWorld.ino │ │ ├── credentials.h.example │ │ └── ssl_cert.h ├── ESP8266MeshIRRemote │ ├── IRBlaster │ │ ├── IRRemote.brd │ │ ├── IRRemote.pdf │ │ ├── IRRemote.sch │ │ ├── bt_regulator.lbr │ │ ├── esp8266modules.lbr │ │ └── transistors.lbr │ ├── Makefile │ ├── README.md │ ├── config.mk │ ├── lib │ │ └── IRremoteESP8266 │ │ │ ├── Contributors.md │ │ │ ├── IRremoteESP8266.cpp │ │ │ ├── IRremoteESP8266.h │ │ │ ├── IRremoteInt.h │ │ │ ├── LICENSE.txt │ │ │ ├── README.md │ │ │ ├── examples │ │ │ ├── IRServer │ │ │ │ └── IRServer.ino │ │ │ ├── IRrecvDemo │ │ │ │ └── IRrecvDemo.ino │ │ │ ├── IRrecvDump │ │ │ │ └── IRrecvDump.ino │ │ │ ├── IRrecvDumpV2 │ │ │ │ └── IRrecvDumpV2.ino │ │ │ ├── IRsendDemo │ │ │ │ └── IRsendDemo.ino │ │ │ └── JVCPanasonicSendDemo │ │ │ │ └── JVCPanasonicSendDemo.ino │ │ │ ├── keywords.txt │ │ │ ├── library.json │ │ │ └── library.properties │ ├── platformio.ini │ └── src │ │ ├── ESP8266MeshIRRemote.ino │ │ └── QueueArray.h └── ESP8266MeshSensor │ ├── Makefile │ ├── README.md │ ├── config.mk │ ├── credentials.h.example │ ├── platformio.ini │ └── src │ ├── ESP8266MeshSensor.ino │ └── capabilities.h ├── library.json ├── library.properties ├── src ├── Base64.cpp ├── Base64.h ├── ESP8266MQTTMesh.cpp ├── ESP8266MQTTMesh.h ├── ESP8266MQTTMeshBuilder.h └── WiFiCompat.h └── utils ├── dump_stacktrace.py ├── gen_server_cert.sh ├── get_mqtt_fingerprint.py └── send_ota.py /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Make sure you have the latest version of ESP8266MQTTMesh before reporting an issue. 2 | 3 | ### Please Provide the following information: 4 | - ESP8266MQTTMesh version: 5 | - AsyncMQTTClient version: 6 | - ESPAsyncTCP version: 7 | - ESP8266 Core version: 8 | 9 | **If you are you using platformio or Arduino, which one?** 10 | 11 | 12 | **Description of problem:** 13 | 14 | 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | credentials.h 2 | libraries 3 | .pioenvs 4 | .piolibdeps 5 | *.swp 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP8266MQTTMesh 2 | Self-assembling mesh network built around the MQTT protocol for the ESP8266 with OTA support 3 | 4 | ## NOTE 2020-04 5 | I no longer have resources to work on this, and there are several issues that need to be addressed. If you have the desire and skill to contribute to this project, please comment on https://github.com/PhracturedBlue/ESP8266MQTTMesh/issues/75 and I will consider your offer of help 6 | 7 | ## Overview 8 | This code provides a library that can build a mesh network between ESP8266 devices that will allow all nodes to communicate 9 | with an MQTT broker. At least one node must be able to see a wiFi router, and there must be a host on the WiFi network running 10 | the MQTT broker. 11 | Nodes cannot (generally) communicate between themselves, but instead forward all messages through the broker. 12 | Each node will expose a hidden AP which can be connected to from any other node on the network. Note: hiding the AP does not provide 13 | any additional security, but does minimize the clutter of other WiFi clients in the area. 14 | 15 | Additionally the library provides an OTA mechanism using the MQTT pathway which can update any/all nodes on the mesh. 16 | 17 | This code was developed primarily for the Sonoff line of relays, but should work with any ESP8266 board with sufficient flash memory 18 | 19 | Further information about the mesh topology can be found [here](docs/MeshTopology.md) 20 | 21 | ### Note for version >= 1.0 22 | As of version 1.0 the nodes no longer need to connect to the broker once before use. Nodes can self-identify other nodes automatically 23 | and do not store any needed state on the broker. Nodes use the MAC address to identify other nodes, and the ESP8266MQTTMesh code 24 | will change the node's MAC address to match the required pattern. The MAC addresses are based on both the node's chipID as well as the mesh password, ensuring that each node will have a unique MAC address as well as that multiple meshes can run in the same area independently. 25 | 26 | Also, he ESP8266MQTTMesh code no longer uses the SPIFFS file-system. If you need it, you'll need to initialize it yourself. If 27 | the mesh is configured to use SSL between nodes, the SSL certs need to be provided during initalization 28 | 29 | ## OTA 30 | While all nodes must run the same version of the ESP8622MQTTMesh library, each node may run a unique firmware with independent purposes. 31 | The main purpose behind this library was to provide a backbone on which several home-automation sensors could be built. As such 32 | each node may need different code to achieve its purpose. Because firmwares are large, and memory is limited on the ESP8266 platform, 33 | there is only a single memory area to hold the incoming firmware. To ensure that a given firmware is only consumed by the proper nodes, 34 | The firmware defines a unique identifier that distinguishes itself from other code. A given firmware is broadcast from the MQTT 35 | broker to all nodes, but only nodes with a matching ID will update. 36 | 37 | ## Using the Library 38 | ### Prerequisites 39 | This library has been converted to use Asynchronous communication for imroved reliability. It requires the following libraries to be installed 40 | * AsyncMqttClient 41 | * ESPAsyncTCP 42 | * Arduino ESP8266 Core version 2.4 43 | 44 | PlatformIO is strongly recommended, and installation instructions can be found [here](http://docs.platformio.org/en/latest/platforms/espressif8266.html)). 45 | 46 | **NOTE:** Enabling SSL will add ~70kB to the firmware size, and may make it impossible to use OTA updates depending on firmware and flash size. 47 | 48 | If OTA support is desired, the esp8266 module must have at least 1M of Flash (configured as >=784k ROM). The OTA image is stored 49 | between the end of the firmware image and the beginning of the filesystem (i.e. not in the filesystem itself) or the end of flash if 50 | no filesystem is present. Thus, ithe maximum firmware size is ~ 1/2 the available Flash. 51 | 52 | ### Library initialization 53 | The ESP8266MQTTMesh only requires 2 parameters to initialize, but there are many additional optional parameters: 54 | ``` 55 | ESP8266MQTTMesh mesh = ESP8266MQTTMesh::Builder(networks, mqtt_server, mqtt_port).build(); 56 | ``` 57 | - `wifi_conn networks[]` *Required*: A list of SSIDs/BSSIDs/passwords to search for to connect to the wireless network. The list should be terminated with a NULL element. 58 | - `const char *mqtt_server` *Required*: Host which runs the MQTT broker 59 | - `int mqtt_port` *Optional*: Port which the MQTT broker is running on. Defaults to 1883 if MQTT SSL is not enabled. Defaults to 8883 is MQTT SSL is enabled 60 | 61 | Additional Parameters can be enabled via the *Builder* for example: 62 | ``` 63 | ESP8266MQTTMesh mesh = ESP8266MQTTMesh::Builder(networks, mqtt_server, mqtt_port) 64 | .setVersion(firmware_ver, firmware_id) 65 | .setMeshPassword(password) 66 | .build(); 67 | ``` 68 | These additional parameters are specified before calling build(), and as few or as many can be used as neeeded. 69 | 70 | ``` 71 | setVersion(firmware_ver, firmware_id) 72 | ``` 73 | - `const char *firmware_ver`: This is a string that idenitfies the firmware. It can be whatever you like. It will be broadcast to the MQTT broker on successful connection 74 | - `int firmware_id`: This identifies a specific node codebase. Each unique firmware should have its own id, and it should not be changed between revisions of the code 75 | 76 | ``` 77 | setMqttAuth(username, password) 78 | ``` 79 | - `const char *username`: The username used to login to the MQTT broker 80 | - `const char *password`: The password used to login to the MQTT broker 81 | 82 | ``` 83 | setMeshPassword(password) 84 | ``` 85 | - `const char *password`: The password to use when a node connects to another node on the mesh. Default: `ESP8266MQTTMesh` 86 | 87 | ``` 88 | setMeshSSID(ssid) 89 | ``` 90 | - `const char *ssid`: The SSID used by mesh nodes. All nodes will use the same SSID, though this isn't noticeable due to nodes using hidden networks. Default: `esp8266_mqtt_mesh 91 | 92 | ``` 93 | setMeshPort(port) 94 | ``` 95 | - `int port`: Port for mesh nodes to listen on for message parsing. Default: `1884` 96 | 97 | ``` 98 | setTopic(in_topic, out_topic) 99 | ``` 100 | - `const char *in_topic`: MQTT topic prefix for messages sent to the node. Default: `esp8266-in/` 101 | - `const char *out_topic`: MQTT topic prefix for messages from the node. Default: `esp8266-out/` 102 | 103 | If SSL support is enabled, the following optional parameters are available: 104 | ``` 105 | setMqttSSL(enable, fingerprint) 106 | ``` 107 | - `bool enable`: Enable MQTT SSL support. Default: `false` 108 | - `const uint8_t *fingerprint`: Fingerprint to verify MQTT certificate (prevent man-in-the-middle attacks) 109 | 110 | ``` 111 | setMeshSSL(cert, cert_len, key, key_len, fingerprint) 112 | ``` 113 | - `const uint8_t *cert`: Certificate 114 | - `uint32_t cert_len`: Certificate length 115 | - `const uint8_t *key`: Certificate key 116 | - `uint32_t key_len`: Certificate key length 117 | - `uint8_t *fingerprint`: Certificate fingerprint (SHA1 of certificate) 118 | 119 | ### Interacting with the mesh 120 | Besides the constructor, the code must call the `begin()` method during setup. 121 | 122 | If messages need to be received by the node, execute the `callback()` function during setup with a function pointer 123 | (prototype: `void callback(const char *topic, const char *payload)`) 124 | 125 | To send messages to the MQTT broker, use one of the publish methods: 126 | ``` 127 | publish(topic, payload, msgCmd) 128 | publish_node(topic, payload, msgCmd) 129 | ``` 130 | The `publish` function sends messages with the `out_topic` prefix, and will not be relayed to any nodes. The `publish_nodes` 131 | function will send messages with the `in_topic` prefix and will be relayed back to all nodes 132 | 133 | - `const char *topic`: the message topic (will be appended to the topic-prefix) 134 | - `const char *payload`: The message to send (must be less than 1152 bytes in length) 135 | - `enum MSG_TYPE msgCmd`: The MQTT Retail/QoS parameters (optional). Must be one of: `MSG_TYPE_NONE`, 136 | `MSG_TYPE_QOS_0`, `MSG_TYPE_QOS_1`, `MSG_TYPE_QOS_2`, `MSG_TYPE_RETAIN_QOS_0`, MSG_TYPE_RETAIN_QOS_1`, 137 | `MSG_TYPE_RETAIN_QOS_2`. Default: `MSG_TYPE_NONE` 138 | 139 | ### SSL support 140 | SSL support is enabled by defining `ASYNC_TCP_SSL_ENABLED=1`. This must be done globally during build. 141 | 142 | Once enabled, SSL can be optionally enabled between the node and the MQTT broker or between mesh nodes (or both). 143 | 144 | #### Using SSL with the MQTT Broker 145 | **WARNING:** Make sure you do not use SHA512 certificate signatures on your MQTT broker. They are not suppoorted by ESP8266 properly 146 | Using an optional fingerprint ensures that the MQTT Broker is the one you expect. Specifying a fingerprint is useful to prevent man-in-the-middle attacks. 147 | The fingerprint can be generated by running: 148 | ``` 149 | utils/get_mqtt_fingerprint.py --host --post 150 | ``` 151 | This will also check the signature to make sure it is compatible with ESP8266 152 | 153 | #### Using SSL between mesh nodes 154 | **NOTE:** Enabling SSL between mesh nodes should not provide additional security, since the mesh connections are already secured via WPA, so enabling this is not recommended 155 | 156 | Generate the certificate, key and fingerprint: 157 | ``` 158 | utils/gen_server_cert.sh 159 | ``` 160 | 161 | Add the resulting ssl_cert.h to your project. then add to the Builder `setMeshSSL(ssl_cert, ssl_cert_len, ssl_key, ssl_key_len, ssl_fingerprint)` 162 | 163 | -------------------------------------------------------------------------------- /docs/MeshTopology.md: -------------------------------------------------------------------------------- 1 | # Mesh Construction and Communication 2 | 3 | ![Mesh Topology](images/MeshTopology.png) 4 | 5 | Nodes always power up in Station mode. Each node in the mesh will 1st try to connect to one of the configured WiFi access-points.i 6 | If the node cannot see any APs, it will next attempt to connect to any nearby nodes. 7 | A potential node is identified by having a hidden SSID and having a specific MAC address. 8 | Each node constructs its MAC address by combining its chipId (upper 3 octets) with the mesh password and generating the lower 3 octets. 9 | The connecting node will check each hidden network's MAC address by calculating the lower 3 octets and verifying that they match the 10 | AP. All matching nodes are sorted by signal strength, and the node will attempt to connect to each in order. 11 | 12 | Once connected, the connecting node will then open a RCP connection on the specified port, and send the mesh password to the AP. Next the 13 | node will broadcast a MQTT message about its availability (ex `esp8266-out/bssid/aabbcc=00:11:22:33:44:55`). This message is sent with the 14 | retain bit set to preserve it on the broker, but it is never consumed by any other nodes. Lastly, the node will start its own AP and begin 15 | listening for connections from other nodes. 16 | 17 | Each node can only handle 4 incoming commections, and will refuse connections once it has reached the limit. While the max connection 18 | count is limited by the ESP8266 core code. The ESP8266MQTTMesh library also assumes this limit. 19 | 20 | If a node loses its connection to the AP, it will also shutdown its own AP. This will result in the subsection of the mesh reorganizing 21 | and rebuilding automatically. It is required that at least one node can see the WiFi AP at any time as the broker must be available 22 | to handle message passing. 23 | 24 | Mesh nodes cannot generally communicate directly with each other. Instead all messages are passed through the MQTT broker. Nodes 25 | automatically subscribe to all topics beginning with the `in_topic` value (typically `esp8266-in/`). 26 | -------------------------------------------------------------------------------- /docs/images/MeshTopology.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PhracturedBlue/ESP8266MQTTMesh/77802c61ffd6ab22f822b625bcfbd04757c35cbe/docs/images/MeshTopology.png -------------------------------------------------------------------------------- /examples/ESP8266MeshHelloWorld/README.md: -------------------------------------------------------------------------------- 1 | # ESP8266MeshHelloWorld 2 | 3 | This is a trivial node that can be used to test the mesh network. 4 | 5 | ## Configuration 6 | a sample configuration is provided in `src/credentials.h.example`. 7 | 8 | 1) First copy `src/credentials.h.example` to `src/credentials.h` 9 | 2) Edit `credentials.h` and modify the configuration to suit your environment 10 | 11 | The following variables should be set: 12 | - *NETWORK_PASSWORD* : Specifies the password of your wireless network 13 | - *NETWORK_LIST* : Specifies the SSIDs of your wireless network 14 | - *MQTT_SERVER* : Specify the IP address of your MQTT broker 15 | - *MQTT_PORT* : Specify the port of your MQTT broker 16 | 17 | The following can optionally be changed: 18 | - *MESH_PASSWORD* : A string used by all nodes to prevent unauthorized access to the mesh network 19 | - *MESH_PORT* : The port that the mesh nodes listen on 20 | 21 | These options are only relevant if the node is compiled with SSL enabled: 22 | - *MESH_SECURE* : Enable SSL bewteen mesh nodes. This requires that the `ssl_cert.h` file is present (Use [this](https://github.com/marvinroger/async-mqtt-client/blob/master/scripts/gen_server_cert.sh) script to generate this header) 23 | - *MQTT_SECURE* : Enable SSL connection to the MQTT broker. 24 | - *MQTT_FINGERPRINT* : a 20-byte string that uniquely identifies your MQTTbroker. A script to retrieve the fingerprint can be found [here](https://github.com/marvinroger/async-mqtt-client/blob/master/scripts/get-fingerprint/get-fingerprint.py) 25 | 26 | ## Compiling and uploading 27 | This example has been designed to use platformio for building and install 28 | Assuming you have already setup a platformio environment: 29 | 30 | ### Non-SSL 31 | `platformio run --target upload` 32 | 33 | ### SSL (Still experimental) 34 | `platformio run -e ssl --target upload` 35 | -------------------------------------------------------------------------------- /examples/ESP8266MeshHelloWorld/data/ssl/fingerprint: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PhracturedBlue/ESP8266MQTTMesh/77802c61ffd6ab22f822b625bcfbd04757c35cbe/examples/ESP8266MeshHelloWorld/data/ssl/fingerprint -------------------------------------------------------------------------------- /examples/ESP8266MeshHelloWorld/data/ssl/server.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PhracturedBlue/ESP8266MQTTMesh/77802c61ffd6ab22f822b625bcfbd04757c35cbe/examples/ESP8266MeshHelloWorld/data/ssl/server.cer -------------------------------------------------------------------------------- /examples/ESP8266MeshHelloWorld/data/ssl/server.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PhracturedBlue/ESP8266MQTTMesh/77802c61ffd6ab22f822b625bcfbd04757c35cbe/examples/ESP8266MeshHelloWorld/data/ssl/server.key -------------------------------------------------------------------------------- /examples/ESP8266MeshHelloWorld/platformio.ini: -------------------------------------------------------------------------------- 1 | # 2 | # Example PlatformIO configuration file for SSL and non-SSL builds. 3 | # 4 | # Before you will be able to build the SSL version of this project, you will 5 | # need to explicitly install the espressif8266_stage platform. 6 | # 7 | # To perform this installation, refer to step 1 of: 8 | # http://docs.platformio.org/en/latest/platforms/espressif8266.html#using-arduino-framework-with-staging-version 9 | 10 | [platformio] 11 | env_default = nossl 12 | 13 | [common] 14 | framework = arduino 15 | lib_deps = ESP8266MQTTMesh 16 | 17 | [env:nossl] 18 | #platform = https://github.com/platformio/platform-espressif8266.git#feature/stage 19 | platform = espressif8266@~1.6.0 20 | board = esp01_1m 21 | framework = ${common.framework} 22 | lib_deps = ${common.lib_deps} 23 | #build_flags = -DLED_PIN=2 -g 24 | 25 | [env:ssl] 26 | platform = espressif8266@~1.6.0 27 | board = esp01_1m 28 | #build_flags = -DASYNC_TCP_SSL_ENABLED=1 -DGATEWAY_ID=10499051 -DLED_PIN=2 -g 29 | build_flags = -DASYNC_TCP_SSL_ENABLED=1 30 | framework = ${common.framework} 31 | lib_deps = ${common.lib_deps} 32 | 33 | [env:esp32_nossl] 34 | platform = espressif32 35 | board = esp32dev 36 | framework = ${common.framework} 37 | lib_deps = ${common.lib_deps} 38 | build_flags = -DLED_PIN=2 -g 39 | 40 | -------------------------------------------------------------------------------- /examples/ESP8266MeshHelloWorld/src/ESP8266MeshHelloWorld.ino: -------------------------------------------------------------------------------- 1 | #include "credentials.h" 2 | #include 3 | #include 4 | 5 | 6 | #ifndef LED_PIN 7 | #define LED_PIN LED_BUILTIN 8 | #endif 9 | 10 | 11 | #define FIRMWARE_ID 0x1337 12 | #define FIRMWARE_VER "0.1" 13 | wifi_conn networks[] = NETWORK_LIST; 14 | const char* mesh_password = MESH_PASSWORD; 15 | const char* mqtt_server = MQTT_SERVER; 16 | const int mqtt_port = MQTT_PORT; 17 | #if ASYNC_TCP_SSL_ENABLED 18 | const uint8_t *mqtt_fingerprint = MQTT_FINGERPRINT; 19 | bool mqtt_secure = MQTT_SECURE; 20 | #if MESH_SECURE 21 | #include "ssl_cert.h" 22 | #endif 23 | #endif 24 | 25 | #ifdef ESP32 26 | String ID = String((unsigned long)ESP.getEfuseMac()); 27 | #else 28 | String ID = String(ESP.getChipId()); 29 | #endif 30 | 31 | 32 | 33 | 34 | unsigned long previousMillis = 0; 35 | const long interval = 5000; 36 | int cnt = 0; 37 | 38 | // Note: All of the '.set' options below are optional. The default values can be 39 | // found in ESP8266MQTTMeshBuilder.h 40 | ESP8266MQTTMesh mesh = ESP8266MQTTMesh::Builder(networks, mqtt_server, mqtt_port) 41 | .setVersion(FIRMWARE_VER, FIRMWARE_ID) 42 | .setMeshPassword(mesh_password) 43 | #if ASYNC_TCP_SSL_ENABLED 44 | .setMqttSSL(mqtt_secure, mqtt_fingerprint) 45 | #if MESH_SECURE 46 | .setMeshSSL(ssl_cert, ssl_cert_len, ssl_key, ssl_key_len, ssl_fingerprint) 47 | #endif //MESH_SECURE 48 | #endif //ASYNC_TCP_SSL_ENABLED 49 | .build(); 50 | 51 | void callback(const char *topic, const char *msg); 52 | 53 | 54 | 55 | void setup() { 56 | 57 | Serial.begin(115200); 58 | delay(1000); //This is only here to make it easier to catch the startup messages. It isn't required 59 | mesh.setCallback(callback); 60 | mesh.begin(); 61 | pinMode(LED_PIN, OUTPUT); 62 | 63 | } 64 | 65 | 66 | void loop() { 67 | 68 | 69 | if (! mesh.connected()) 70 | return; 71 | 72 | unsigned long currentMillis = millis(); 73 | 74 | if (currentMillis - previousMillis >= interval) { 75 | 76 | String cntStr = String(cnt); 77 | String msg = "hello from " + ID + " cnt: " + cntStr; 78 | mesh.publish(ID.c_str(), msg.c_str()); 79 | previousMillis = currentMillis; 80 | cnt++; 81 | 82 | } 83 | 84 | } 85 | 86 | 87 | 88 | void callback(const char *topic, const char *msg) { 89 | 90 | 91 | if (0 == strcmp(topic, (const char*) ID.c_str())) { 92 | if(String(msg) == "0") { 93 | digitalWrite(LED_PIN, HIGH); 94 | }else{ 95 | digitalWrite(LED_PIN, LOW); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /examples/ESP8266MeshHelloWorld/src/credentials.h.example: -------------------------------------------------------------------------------- 1 | #define NETWORK_PASSWORD "network password" 2 | #define NETWORK_LIST { \ 3 | WIFI_CONN("ssid 1", NETWORK_PASSWORD, NULL, 0), \ 4 | WIFI_CONN("ssid 2", NETWORK_PASSWORD, NULL, 0), \ 5 | NULL, \ 6 | } 7 | #define MESH_PASSWORD "esp8266_sensor_mesh" 8 | #define MQTT_SERVER "MQTT Server IP Address" 9 | #define MQTT_PORT 1883 10 | 11 | /* Only used if SSL is enabled */ 12 | #define MESH_SECURE true 13 | #define MQTT_SECURE false 14 | #define MQTT_FINGERPRINT NULL 15 | //const uint8_t MQTT_FINGERPRINT[] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x00,0x11,0x22,0x33}; 16 | 17 | -------------------------------------------------------------------------------- /examples/ESP8266MeshHelloWorld/src/ssl_cert.h: -------------------------------------------------------------------------------- 1 | const uint8_t ssl_key[] = 2 | "\x30\x82\x02\x5D\x02\x01\x00\x02\x81\x81\x00\xA6\xE5\xE8\x1A\xFB" 3 | "\xF8\x1A\xB7\x34\xCF\x98\x90\x10\x7A\x80\x1D\x1C\x3F\xA7\x9A\xC0" 4 | "\x97\x5D\xC2\xCF\xD0\xD6\xCE\x65\x11\x57\xB5\x4A\x21\x81\x5E\x66" 5 | "\xBE\x05\x70\xDC\xF3\x5C\x8D\x40\x12\x03\x22\xAC\x75\x26\x92\x04" 6 | "\x1F\xC1\x9D\x6F\x68\x4E\x70\xE9\x43\xF1\xD0\xF2\x2F\x68\xDE\xA5" 7 | "\x9A\xBA\xF6\xCA\x53\xA4\x89\x49\xD8\x9C\x65\x7C\x02\x7B\xBF\xFC" 8 | "\x66\x56\xA6\x55\x45\x71\x8B\x31\x3F\xEC\xA0\x65\x0B\x76\x6F\xE5" 9 | "\x08\x67\xDF\x8A\x9E\x8B\x46\x29\x63\x71\x84\xED\x57\xC2\xBC\x37" 10 | "\x79\xA2\x3F\xFA\x39\xD3\xEA\xBF\x7A\xCB\x83\x02\x03\x01\x00\x01" 11 | "\x02\x81\x80\x21\xCB\x2F\xA2\x37\x1E\xD7\x99\xFD\x11\x83\xDC\xB7" 12 | "\xD9\x76\x13\x6E\xE2\xDC\xB7\x13\x04\x13\x32\x1D\x0E\x36\x50\x78" 13 | "\x5A\x78\x9D\xF6\xB2\xAE\x15\x45\x4C\x78\xA1\x8F\xBB\x9F\x23\xE2" 14 | "\xB3\x42\xFB\x44\x5C\x3C\x41\x18\xA0\xAD\x7D\x89\x4F\x5F\x82\xB1" 15 | "\x58\xD6\x9F\x9A\x8F\x3A\x2C\x5C\xE4\xED\xEC\x5E\x95\xDB\x59\x66" 16 | "\xEE\xF3\xAB\x95\x3E\x3D\xF6\xC0\xFD\x13\x38\x78\x1D\xC8\xE2\x08" 17 | "\xAC\x3B\xA5\x1F\xC8\x64\xD2\xD2\xC4\x3E\xD1\xC0\x4B\xC2\xC8\x56" 18 | "\x94\xC1\xE5\xA1\x5C\x57\x7E\x56\x5E\xC1\x33\x80\x7F\x07\x33\xD8" 19 | "\x0B\xD5\xC1\x02\x41\x00\xD3\x95\x14\xE1\xC1\xAB\xEF\x19\x66\x6C" 20 | "\xFE\xDB\xB3\x75\xD0\xEA\x1C\x2C\x17\x2A\x3F\x6D\x79\xCA\xA9\x82" 21 | "\x7F\x19\x98\xC0\x1F\x96\x0A\x6B\x86\x01\xAE\x4E\xEA\x99\x48\x65" 22 | "\x61\xC8\xB1\xC1\xDC\x20\xFF\xEE\x3A\xB3\x10\xCE\x4B\xEF\x6C\xD0" 23 | "\x60\x44\x68\x33\x45\x13\x02\x41\x00\xC9\xEF\x63\xDA\x7D\xF8\x8A" 24 | "\xC9\xD1\x96\xBE\x13\xB6\x3F\xB6\x04\xF1\xD7\x06\x89\xCC\x2D\x5E" 25 | "\xDA\x9A\x78\xA7\xAC\x40\x37\x2E\x5C\x1F\x7C\x64\x6D\x4B\xB1\x78" 26 | "\xD6\x62\x5F\x60\x95\xC9\x7B\xD7\x03\x54\x46\x98\xD8\x4E\xA8\xB8" 27 | "\xC6\x32\xD8\xC5\x32\xAE\xCA\xDD\xD1\x02\x40\x57\x37\x61\xF7\x39" 28 | "\x85\x6D\x37\x14\x30\xA3\xD1\xDE\xA5\x17\x2C\x19\xD6\xD6\xE9\xB4" 29 | "\x61\xA5\x4D\xB4\x18\x35\xDA\x50\x4C\x09\xF9\x28\x6C\x70\x3D\xEB" 30 | "\x23\x5E\xB3\x36\xD3\x8B\xBE\x55\xFF\xEA\x84\xB3\xDA\xF8\xD9\x6D" 31 | "\x79\x0C\x76\x32\x6D\xA6\xF1\x2B\xDE\xCE\x7F\x02\x41\x00\x89\xD6" 32 | "\x0B\xB4\x92\x13\xDA\xB8\x53\x85\xAF\x8C\xC8\xF3\xC8\x0C\xAB\xFE" 33 | "\xF8\x09\x8B\x02\xD5\x22\x26\x1A\x81\x69\x04\x14\x26\x62\xDF\x63" 34 | "\x0B\x31\xC7\x5F\x06\x7A\x5F\x7F\x76\xF0\x07\x2D\xAE\xE0\x28\xE0" 35 | "\x5F\x68\x16\x98\xF8\x36\xE1\x72\x31\x78\x9C\xF3\x00\x61\x02\x41" 36 | "\x00\xB5\x07\xCF\xC3\x62\x65\xD3\xD4\x97\x2B\xCA\x6B\x66\x75\x5C" 37 | "\xE1\x38\xFD\xAF\xC2\xA9\xCE\x21\x3F\x09\xDC\xEA\xEE\xD2\x09\xF8" 38 | "\xCF\xF6\x8D\xEC\x95\xF2\x12\xAC\xE7\x11\x30\xE3\xC6\xDB\x26\x17" 39 | "\x64\xB1\xC2\x78\xF0\x47\x75\x11\xA9\x69\x52\x23\xC3\x2B\x37\x4B" 40 | "\xBB" 41 | ; 42 | const uint32_t ssl_key_len = 609; 43 | const uint8_t ssl_cert[] = 44 | "\x30\x82\x02\x47\x30\x82\x01\x2F\x02\x09\x00\xD2\x15\x44\x99\x56" 45 | "\xC9\xF0\xD1\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05" 46 | "\x05\x00\x30\x1C\x31\x1A\x30\x18\x06\x03\x55\x04\x0A\x0C\x11\x45" 47 | "\x73\x70\x72\x65\x73\x73\x69\x66\x20\x53\x79\x73\x74\x65\x6D\x73" 48 | "\x30\x1E\x17\x0D\x31\x37\x30\x37\x31\x31\x30\x33\x30\x33\x31\x32" 49 | "\x5A\x17\x0D\x33\x31\x30\x33\x32\x30\x30\x33\x30\x33\x31\x32\x5A" 50 | "\x30\x33\x31\x19\x30\x17\x06\x03\x55\x04\x0A\x0C\x10\x61\x78\x54" 51 | "\x4C\x53\x20\x6F\x6E\x20\x45\x53\x50\x38\x32\x36\x36\x31\x16\x30" 52 | "\x14\x06\x03\x55\x04\x03\x0C\x0D\x65\x73\x70\x38\x32\x36\x36\x2E" 53 | "\x6C\x6F\x63\x61\x6C\x30\x81\x9F\x30\x0D\x06\x09\x2A\x86\x48\x86" 54 | "\xF7\x0D\x01\x01\x01\x05\x00\x03\x81\x8D\x00\x30\x81\x89\x02\x81" 55 | "\x81\x00\xA6\xE5\xE8\x1A\xFB\xF8\x1A\xB7\x34\xCF\x98\x90\x10\x7A" 56 | "\x80\x1D\x1C\x3F\xA7\x9A\xC0\x97\x5D\xC2\xCF\xD0\xD6\xCE\x65\x11" 57 | "\x57\xB5\x4A\x21\x81\x5E\x66\xBE\x05\x70\xDC\xF3\x5C\x8D\x40\x12" 58 | "\x03\x22\xAC\x75\x26\x92\x04\x1F\xC1\x9D\x6F\x68\x4E\x70\xE9\x43" 59 | "\xF1\xD0\xF2\x2F\x68\xDE\xA5\x9A\xBA\xF6\xCA\x53\xA4\x89\x49\xD8" 60 | "\x9C\x65\x7C\x02\x7B\xBF\xFC\x66\x56\xA6\x55\x45\x71\x8B\x31\x3F" 61 | "\xEC\xA0\x65\x0B\x76\x6F\xE5\x08\x67\xDF\x8A\x9E\x8B\x46\x29\x63" 62 | "\x71\x84\xED\x57\xC2\xBC\x37\x79\xA2\x3F\xFA\x39\xD3\xEA\xBF\x7A" 63 | "\xCB\x83\x02\x03\x01\x00\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7" 64 | "\x0D\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\x5F\x4F\xA6\x53\x1D" 65 | "\xC2\x7C\x2C\x0D\xDE\x54\x05\xAD\x61\xDE\x39\xE2\x8B\xA9\x47\x0D" 66 | "\x57\xC3\xC0\x15\x18\x0C\xBF\x71\x32\x5A\x8E\x68\x64\x7A\xA2\xE3" 67 | "\x27\x76\xC4\x22\x16\x31\x7A\x14\xD7\x2B\x16\x1E\x94\x2F\x69\x51" 68 | "\xFF\xE0\xBC\x84\xD7\x6B\x51\xC1\xA7\x45\x1E\x6E\xB4\x86\x4F\xDD" 69 | "\x07\x15\x72\x4B\x12\x79\xEF\x31\xDE\xE4\x9E\xC6\x6F\xDA\x36\xC8" 70 | "\x59\x1B\x6A\x3E\xF0\xDE\xD7\x84\xCE\xE7\xAE\x59\xBE\xB6\x2D\xB0" 71 | "\xD3\x84\x8F\xD6\xA2\x6F\x2F\x9E\x22\x5B\x1D\x61\xCF\x96\xB3\x62" 72 | "\x16\x63\xC7\x8A\xA8\xC8\x7C\xE0\xB5\x98\xAE\x12\xB1\xAE\xE5\xFF" 73 | "\x1F\x1A\x0D\x15\x7C\x26\xF0\x19\xBF\x12\x70\xB3\x29\xF1\xA0\x14" 74 | "\x64\x52\x08\x56\x88\xBF\x54\xCF\x5C\x44\x50\x25\xB9\xF4\xC3\x29" 75 | "\x3B\xB2\x98\xC8\xE2\xB9\x76\x78\x0E\xDB\x8E\x52\x8B\x4D\x7B\x95" 76 | "\xDB\xCB\xE8\x68\x67\x3B\x6F\x99\x0E\xDC\x4D\x81\x93\xB2\xA3\x99" 77 | "\xD2\xBC\x1E\xB4\x4F\x9D\xC0\x11\xEF\x10\xD4\xA8\x32\xEC\xE3\xFE" 78 | "\xA8\x52\x57\x4F\x04\x3D\x17\x9B\xF1\x3C\x19\xAB\x17\x03\x66\x69" 79 | "\x90\x8A\x7B\x09\xDF\xF9\x78\xE6\xC6\xED\x04\x19\x2B\x88\xD4\xE1" 80 | "\x80\x88\x1A\x98\x6F\x9C\x6D\x37\x18\x55\x36" 81 | ; 82 | const uint32_t ssl_cert_len = 587; 83 | 84 | const uint8_t ssl_fingerprint[] = 85 | "\xC8\x03\xFF\xF8\xD0\x8D\xB8\xE7\x11\xF0\x87\x2C\x57\x4E\xDD\xD3" 86 | "\x48\x2C\x35\x64" 87 | ; 88 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/IRBlaster/IRRemote.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PhracturedBlue/ESP8266MQTTMesh/77802c61ffd6ab22f822b625bcfbd04757c35cbe/examples/ESP8266MeshIRRemote/IRBlaster/IRRemote.pdf -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/IRBlaster/transistors.lbr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PhracturedBlue/ESP8266MQTTMesh/77802c61ffd6ab22f822b625bcfbd04757c35cbe/examples/ESP8266MeshIRRemote/IRBlaster/transistors.lbr -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/Makefile: -------------------------------------------------------------------------------- 1 | #==================================================================================== 2 | # makeESPArduino 3 | # 4 | # A makefile for ESP8286 and ESP32 Arduino projects. 5 | # Edit the contents of this file to suit your project 6 | # or just include it and override the applicable macros. 7 | # 8 | # License: GPL 2.1 9 | # General and full license information is available at: 10 | # https://github.com/plerup/makeEspArduino 11 | # 12 | # Copyright (c) 2016-2017 Peter Lerup. All rights reserved. 13 | # 14 | #==================================================================================== 15 | 16 | #==================================================================================== 17 | # Project specfic values 18 | #==================================================================================== 19 | 20 | # Include possible project makefile. This can be used to override the defaults below 21 | -include $(firstword $(PROJ_CONF) $(dir $(SKETCH))config.mk) 22 | 23 | #=== Default values not available in the Arduino configuration files 24 | 25 | CHIP ?= esp8266 26 | 27 | # Set chip specific default board unless specified 28 | BOARD ?= $(if $(filter $(CHIP), esp32),esp32,generic) 29 | 30 | # Serial flashing parameters 31 | UPLOAD_PORT ?= $(shell ls -1tr /dev/ttyUSB* | tail -1) 32 | UPLOAD_VERB ?= -v 33 | 34 | # OTA parameters 35 | ESP_ADDR ?= ESP_123456 36 | ESP_PORT ?= 8266 37 | ESP_PWD ?= 123 38 | 39 | # HTTP update parameters 40 | HTTP_ADDR ?= ESP_123456 41 | HTTP_URI ?= /update 42 | HTTP_PWD ?= user 43 | HTTP_USR ?= password 44 | 45 | # Output directory 46 | BUILD_DIR ?= /tmp/mkESP/$(MAIN_NAME)_$(BOARD) 47 | 48 | # File system source directory 49 | FS_DIR ?= $(dir $(SKETCH))data 50 | 51 | # Bootloader 52 | BOOT_LOADER ?= $(ESP_ROOT)/bootloaders/eboot/eboot.elf 53 | 54 | #==================================================================================== 55 | # Standard build logic and values 56 | #==================================================================================== 57 | 58 | START_TIME := $(shell perl -e "print time();") 59 | 60 | # Utility functions 61 | git_description = $(shell git -C $(1) describe --tags --always --dirty 2>/dev/null || echo Unknown) 62 | time_string = $(shell date +$(1)) 63 | 64 | # ESP Arduino directories 65 | ifndef ESP_ROOT 66 | # Location not defined, find and use possible version in the Arduino IDE installation 67 | OS ?= $(shell uname -s) 68 | ifeq ($(OS), Windows_NT) 69 | ARDUINO_DIR = $(shell cygpath -m $(LOCALAPPDATA)/Arduino15/packages/$(CHIP)) 70 | else ifeq ($(OS), Darwin) 71 | ARDUINO_DIR = $(HOME)/Library/Arduino15/packages/$(CHIP) 72 | else 73 | ARDUINO_DIR = $(HOME)/.arduino15/packages/$(CHIP) 74 | endif 75 | ESP_ROOT := $(lastword $(wildcard $(ARDUINO_DIR)/hardware/$(CHIP)/*)) 76 | ifeq ($(ESP_ROOT),) 77 | $(error No installed version of $(CHIP) Arduino found) 78 | endif 79 | ESP_ARDUINO_VERSION := $(notdir $(ESP_ROOT)) 80 | # Find used version of compiler and tools 81 | COMP_PATH := $(lastword $(wildcard $(ARDUINO_DIR)/tools/xtensa-lx106-elf-gcc/*)) 82 | ESPTOOL_PATH := $(lastword $(wildcard $(ARDUINO_DIR)/tools/esptool/*)) 83 | MKSPIFFS_PATH := $(lastword $(wildcard $(ARDUINO_DIR)/tools/mkspiffs/*)) 84 | else 85 | # Location defined, assume it is a git clone 86 | ESP_ARDUINO_VERSION = $(call git_description,$(ESP_ROOT)) 87 | endif 88 | ESP_LIBS = $(ESP_ROOT)/libraries 89 | SDK_ROOT = $(ESP_ROOT)/tools/sdk 90 | TOOLS_ROOT = $(ESP_ROOT)/tools 91 | 92 | ifeq ($(wildcard $(ESP_ROOT)/cores/$(CHIP)),) 93 | $(error $(ESP_ROOT) is not a vaild directory for $(CHIP)) 94 | endif 95 | 96 | ESPTOOL_PY = esptool.py --baud=$(UPLOAD_SPEED) --port $(UPLOAD_PORT) 97 | 98 | # Search for sketch if not defined 99 | SKETCH := $(realpath $(firstword \ 100 | $(SKETCH) \ 101 | $(wildcard *.ino) \ 102 | $(if $(filter $(CHIP), esp32),$(ESP_LIBS)/WiFi/examples/WiFiScan/WiFiScan.ino,$(ESP_LIBS)/ESP8266WebServer/examples/HelloServer/HelloServer.ino) \ 103 | ) \ 104 | ) 105 | ifeq ($(wildcard $(SKETCH)),) 106 | $(error Sketch $(SKETCH) not found) 107 | endif 108 | 109 | # Main output definitions 110 | MAIN_NAME := $(basename $(notdir $(SKETCH))) 111 | MAIN_EXE = $(BUILD_DIR)/$(MAIN_NAME).bin 112 | FS_IMAGE = $(BUILD_DIR)/FS.spiffs 113 | 114 | ifeq ($(OS), Windows_NT) 115 | # Adjust critical paths 116 | BUILD_DIR := $(shell cygpath -m $(BUILD_DIR)) 117 | SKETCH := $(shell cygpath -m $(SKETCH)) 118 | endif 119 | 120 | # Build file extensions 121 | OBJ_EXT = .o 122 | DEP_EXT = .d 123 | 124 | # Special tool definitions 125 | OTA_TOOL ?= $(TOOLS_ROOT)/espota.py 126 | HTTP_TOOL ?= curl 127 | 128 | # Core source files 129 | CORE_DIR = $(ESP_ROOT)/cores/$(CHIP) 130 | CORE_SRC := $(shell find $(CORE_DIR) -name "*.S" -o -name "*.c" -o -name "*.cpp") 131 | CORE_OBJ := $(patsubst %,$(BUILD_DIR)/%$(OBJ_EXT),$(notdir $(CORE_SRC))) 132 | CORE_LIB = $(BUILD_DIR)/arduino.ar 133 | 134 | # User defined compilation units and directories 135 | ifeq ($(LIBS),) 136 | # Automatically find directories with header files used by the sketch 137 | FINDCMD := perl -e 'use File::Find;@d = split(" ", shift);while (<>) {$$f{"$$1"} = 1 if /^\s*\#include\s+[<"]([^>"]+)/;}find({follow => 1, wanted => sub {return if($$File::Find::dir =~ /examples|tests/);print $$File::Find::dir," " if $$f{$$_}}}, @d);' 138 | LIBS := $(shell $(FINDCMD) "$(ESP_LIBS) $(HOME)/Arduino/libraries" $(SKETCH) ../../src/*.cpp ../../src/*.h) 139 | ifeq ($(LIBS),) 140 | # No dependencies found 141 | LIBS = /dev/null 142 | endif 143 | endif 144 | IGNORE_PATTERN := $(foreach dir,$(EXCLUDE_DIRS),$(dir)/%) 145 | SKETCH_DIR = $(dir $(SKETCH)) 146 | USER_INC := $(filter-out $(IGNORE_PATTERN),$(shell find -L $(SKETCH_DIR) $(LIBS) -name "*.h")) 147 | USER_SRC := $(SKETCH) $(filter-out $(IGNORE_PATTERN),$(shell find -L $(SKETCH_DIR) $(LIBS) -name "*.S" -o -name "*.c" -o -name "*.cpp")) 148 | # Object file suffix seems to be significant for the linker... 149 | USER_OBJ := $(subst .ino,_.cpp,$(patsubst %,$(BUILD_DIR)/%$(OBJ_EXT),$(notdir $(USER_SRC)))) 150 | USER_DIRS := $(sort $(dir $(USER_SRC))) 151 | USER_INC_DIRS := $(sort $(dir $(USER_INC))) 152 | 153 | # Use first flash definition for the board as default 154 | FLASH_DEF ?= $(shell cat $(ESP_ROOT)/boards.txt | perl -e 'while (<>) {if (/^$(BOARD)\.menu\.FlashSize\.([^\.]+)=/){ print "$$1"; exit;}} print "NA";') 155 | 156 | # The actual build commands are to be extracted from the Arduino description files 157 | ARDUINO_MK = $(BUILD_DIR)/arduino.mk 158 | ARDUINO_DESC := $(shell find $(ESP_ROOT) -maxdepth 1 -name "*.txt" | sort) 159 | $(ARDUINO_MK): $(ARDUINO_DESC) $(MAKEFILE_LIST) | $(BUILD_DIR) 160 | perl -e "$$PARSE_ARDUINO" $(BOARD) $(FLASH_DEF) $(ARDUINO_EXTRA_DESC) $(ARDUINO_DESC) >$(ARDUINO_MK) 161 | 162 | -include $(ARDUINO_MK) 163 | 164 | # Compilation directories and path 165 | INCLUDE_DIRS += $(CORE_DIR) $(ESP_ROOT)/variants/$(INCLUDE_VARIANT) $(BUILD_DIR) 166 | C_INCLUDES := $(foreach dir,$(INCLUDE_DIRS) $(USER_INC_DIRS),-I$(dir)) 167 | VPATH += $(shell find $(CORE_DIR) -type d) $(USER_DIRS) 168 | 169 | # Automatically generated build information data 170 | # Makes the build date and git descriptions at the actual build event available as string constants in the program 171 | BUILD_INFO_H = $(BUILD_DIR)/buildinfo.h 172 | BUILD_INFO_CPP = $(BUILD_DIR)/buildinfo.c++ 173 | BUILD_INFO_OBJ = $(BUILD_INFO_CPP)$(OBJ_EXT) 174 | 175 | $(BUILD_INFO_H): | $(BUILD_DIR) 176 | echo "typedef struct { const char *date, *time, *src_version, *env_version;} _tBuildInfo; extern _tBuildInfo _BuildInfo;" >$@ 177 | 178 | # Build rules for the different source file types 179 | $(BUILD_DIR)/%.cpp$(OBJ_EXT): %.cpp $(BUILD_INFO_H) $(ARDUINO_MK) 180 | echo $(' >$(BUILD_INFO_CPP) 208 | echo '_tBuildInfo _BuildInfo = {"$(BUILD_DATE)","$(BUILD_TIME)","$(SRC_GIT_VERSION)","$(ESP_ARDUINO_VERSION)"};' >>$(BUILD_INFO_CPP) 209 | $(CPP_COM) $(BUILD_INFO_CPP) -o $(BUILD_INFO_OBJ) 210 | $(LD_COM) 211 | $(GEN_PART_COM) 212 | $(ELF2BIN_COM) 213 | $(SIZE_COM) | perl -e "$$MEM_USAGE" "$(MEM_FLASH)" "$(MEM_RAM)" 214 | ifneq ($(FLASH_INFO),) 215 | printf "Flash size: $(FLASH_INFO)\n\n" 216 | endif 217 | perl -e 'print "Build complete. Elapsed time: ", time()-$(START_TIME), " seconds\n\n"' 218 | 219 | upload flash: all 220 | $(UPLOAD_COM) 221 | 222 | ota: all 223 | $(OTA_TOOL) -i $(ESP_ADDR) -p $(ESP_PORT) -a $(ESP_PWD) -f $(MAIN_EXE) 224 | 225 | http: all 226 | $(HTTP_TOOL) --verbose -F image=@$(MAIN_EXE) --user $(HTTP_USR):$(HTTP_PWD) http://$(HTTP_ADDR)$(HTTP_URI) 227 | echo "\n" 228 | 229 | $(FS_IMAGE): $(wildcard $(FS_DIR)/*) 230 | ifneq ($(CHIP),esp32) 231 | echo Generating filesystem image: $(FS_IMAGE) 232 | $(MKSPIFFS_COM) 233 | else 234 | echo No SPIFFS function available for $(CHIP) 235 | exit 1 236 | endif 237 | 238 | fs: $(FS_IMAGE) 239 | 240 | upload_fs flash_fs: $(FS_IMAGE) 241 | $(FS_UPLOAD_COM) 242 | 243 | FLASH_FILE ?= esp_flash.bin 244 | dump_flash: 245 | echo Dumping flash memory to file: $(FLASH_FILE) 246 | $(ESPTOOL_PY) read_flash 0 $(shell perl -e 'shift =~ /(\d+)([MK])/ || die "Invalid memory size\n";$$mem_size=$$1*1024;$$mem_size*=1024 if $$2 eq "M";print $$mem_size;' $(FLASH_DEF)) $(FLASH_FILE) 247 | 248 | restore_flash: 249 | echo Restoring flash memory from file: $(FLASH_FILE) 250 | $(ESPTOOL_PY) write_flash -fs $(shell perl -e 'shift =~ /(\d+)([MK])/ || die "Invalid memory size\n";print ($$2 eq "K" ? 2 : $$1*8);' $(FLASH_DEF))m -fm $(FLASH_MODE) -ff $(FLASH_SPEED)m 0 $(FLASH_FILE) 251 | 252 | clean: 253 | echo Removing all build files 254 | rm -rf $(BUILD_DIR)/* 255 | 256 | list_boards: 257 | echo === Available boards === 258 | cat $(ESP_ROOT)/boards.txt | perl -e 'while (<>) { if (/^(\w+)\.name=(.+)/){ print sprintf("%-20s %s\n", $$1,$$2);} }' 259 | 260 | list_lib: 261 | echo === User specific libraries === 262 | perl -e 'foreach (@ARGV) {print "$$_\n"}' "* Include directories:" $(USER_INC_DIRS) "* Library source files:" $(USER_SRC) "Foo" $(IGNORE_PATTERN) 263 | 264 | list_flash_defs: 265 | echo === Memory configurations for board: $(BOARD) === 266 | cat $(ESP_ROOT)/boards.txt | perl -e 'while (<>) { if (/^$(BOARD)\.menu\.FlashSize.([^\.]+)=(.+)/){ print sprintf("%-10s %s\n", $$1,$$2);} }' 267 | 268 | help: 269 | echo 270 | echo "Generic makefile for building Arduino esp8266 and esp32 projects" 271 | echo "This file can either be used directly or included from another makefile" 272 | echo "" 273 | echo "The following targets are available:" 274 | echo " all (default) Build the project application" 275 | echo " clean Remove all intermediate build files" 276 | echo " flash Build and and flash the project application" 277 | echo " flash_fs Build and and flash file system (when applicable)" 278 | echo " ota Build and and flash via OTA" 279 | echo " Params: ESP_ADDR, ESP_PORT and ESP_PWD" 280 | echo " http Build and and flash via http (curl)" 281 | echo " Params: HTTP_ADDR, HTTP_URI, HTTP_PWD and HTTP_USR" 282 | echo " dump_flash Dump the whole board flash memory to a file" 283 | echo " restore_flash Restore flash memory from a previously dumped file" 284 | echo " list_lib Show a list of used library files and include paths" 285 | echo "Configurable parameters:" 286 | echo " SKETCH Main source file" 287 | echo " If not specified the first sketch in current" 288 | echo " directory will be used. If none is found there," 289 | echo " a demo example will be used instead." 290 | echo " LIBS Includes in the sketch file of libraries from within" 291 | echo " the ESP Arduino directories are automatically" 292 | echo " detected. If this is not enough, define this" 293 | echo " variable with all libraries or directories needed." 294 | echo " USER_LIBS Path to user installed Arduino libraries" 295 | echo " CHIP Set to esp8266 or esp32. Default: '$(CHIP)'" 296 | echo " BOARD Name of the target board. Default: '$(BOARD)'" 297 | echo " Use 'list_boards' to get list of available ones" 298 | echo " FLASH_DEF Flash partitioning info. Default '$(FLASH_DEF)'" 299 | echo " Use 'list_flash_defs' to get list of available ones" 300 | echo " BUILD_DIR Directory for intermediate build files." 301 | echo " Default '$(BUILD_DIR)'" 302 | echo " BUILD_EXTRA_FLAGS Additional parameters for the compilation commands" 303 | echo " FS_DIR File system root directory" 304 | echo " UPLOAD_PORT Serial flashing port name. Default: '$(UPLOAD_PORT)'" 305 | echo " UPLOAD_SPEED Serial flashing baud rate. Default: '$(UPLOAD_SPEED)'" 306 | echo " FLASH_FILE File name for dump and restore flash operations" 307 | echo " Default: '$(FLASH_FILE)'" 308 | echo " VERBOSE Set to 1 to get full printout of the build" 309 | echo " SINGLE_THREAD Use only one build thread" 310 | echo 311 | 312 | $(BUILD_DIR): 313 | mkdir -p $(BUILD_DIR) 314 | 315 | .PHONY: all 316 | all: $(BUILD_DIR) $(ARDUINO_MK) $(BUILD_INFO_H) prebuild $(MAIN_EXE) 317 | 318 | prebuild: 319 | ifdef USE_PREBUILD 320 | $(PREBUILD_COM) 321 | endif 322 | 323 | # Include all available dependencies 324 | -include $(wildcard $(BUILD_DIR)/*$(DEP_EXT)) 325 | 326 | .DEFAULT_GOAL = all 327 | 328 | ifndef SINGLE_THREAD 329 | # Use multithreaded builds by default 330 | MAKEFLAGS += -j 331 | endif 332 | 333 | ifndef VERBOSE 334 | # Set silent mode as default 335 | MAKEFLAGS += --silent 336 | endif 337 | 338 | # Inline Perl scripts 339 | 340 | # Parse Arduino definitions and build commands from the descriptions 341 | define PARSE_ARDUINO 342 | my $$board = shift; 343 | my $$flashSize = shift; 344 | my %v; 345 | 346 | sub def_var { 347 | my ($$name, $$var) = @_; 348 | print "$$var ?= $$v{$$name}\n"; 349 | $$v{$$name} = "\$$($$var)"; 350 | } 351 | 352 | $$v{'runtime.platform.path'} = '$$(ESP_ROOT)'; 353 | $$v{'includes'} = '$$(C_INCLUDES)'; 354 | $$v{'runtime.ide.version'} = '10605'; 355 | $$v{'build.arch'} = '$$(CHIP)'; 356 | $$v{'build.project_name'} = '$$(MAIN_NAME)'; 357 | $$v{'build.path'} = '$$(BUILD_DIR)'; 358 | $$v{'object_files'} = '$$^ $$(BUILD_INFO_OBJ)'; 359 | 360 | foreach my $$fn (@ARGV) { 361 | open($$f, $$fn) || die "Failed to open: $$fn\n"; 362 | while (<$$f>) { 363 | next unless /^(\w[\w\-\.]+)=(.*)/; 364 | my ($$key, $$val) =($$1, $$2); 365 | $$board_defined = 1 if $$key eq "$$board.name"; 366 | $$key =~ s/$$board\.menu\.FlashSize\.$$flashSize\.//; 367 | $$key =~ s/$$board\.menu\.FlashFreq\.[^\.]+\.//; 368 | $$key =~ s/$$board\.menu\.UploadSpeed\.[^\.]+\.//; 369 | $$key =~ s/^$$board\.//; 370 | $$v{$$key} ||= $$val; 371 | } 372 | close($$f); 373 | } 374 | $$v{'runtime.tools.xtensa-lx106-elf-gcc.path'} ||= '$$(COMP_PATH)'; 375 | $$v{'runtime.tools.esptool.path'} ||= '$$(ESPTOOL_PATH)'; 376 | $$v{'runtime.tools.mkspiffs.path'} ||= '$$(MKSPIFFS_PATH)'; 377 | 378 | die "* Uknown board $$board\n" unless $$board_defined; 379 | 380 | print "# Board definitions\n"; 381 | def_var('build.f_cpu', 'F_CPU'); 382 | def_var('build.flash_mode', 'FLASH_MODE'); 383 | def_var('build.flash_freq', 'FLASH_SPEED'); 384 | def_var('upload.resetmethod', 'UPLOAD_RESET'); 385 | def_var('upload.speed', 'UPLOAD_SPEED'); 386 | def_var('compiler.warning_flags', 'COMP_WARNINGS'); 387 | $$v{'upload.verbose'} = '$$(UPLOAD_VERB)'; 388 | $$v{'serial.port'} = '$$(UPLOAD_PORT)'; 389 | $$v{'recipe.objcopy.hex.pattern'} =~ s/[^"]+\/bootloaders\/eboot\/eboot.elf/\$$(BOOT_LOADER)/; 390 | $$v{'tools.esptool.upload.pattern'} =~ s/\{(cmd|path)\}/\{tools.esptool.$$1\}/g; 391 | $$v{'compiler.cpreprocessor.flags'} .= " \$$(C_PRE_PROC_FLAGS)"; 392 | $$v{'build.extra_flags'} .= " \$$(BUILD_EXTRA_FLAGS)"; 393 | 394 | foreach my $$key (sort keys %v) { 395 | while ($$v{$$key} =~/\{/) { 396 | $$v{$$key} =~ s/\{([\w\-\.]+)\}/$$v{$$1}/; 397 | $$v{$$key} =~ s/""//; 398 | } 399 | $$v{$$key} =~ s/ -o $$//; 400 | $$v{$$key} =~ s/(-D\w+=)"([^"]+)"/$$1\\"$$2\\"/g; 401 | } 402 | 403 | print "INCLUDE_VARIANT = $$v{'build.variant'}\n"; 404 | print "# Commands\n"; 405 | print "C_COM=$$v{'recipe.c.o.pattern'}\n"; 406 | print "CPP_COM=$$v{'recipe.cpp.o.pattern'}\n"; 407 | print "S_COM=$$v{'recipe.S.o.pattern'}\n"; 408 | print "AR_COM=$$v{'recipe.ar.pattern'}\n"; 409 | print "LD_COM=$$v{'recipe.c.combine.pattern'}\n"; 410 | print "GEN_PART_COM=$$v{'recipe.objcopy.eep.pattern'}\n"; 411 | print "ELF2BIN_COM=$$v{'recipe.objcopy.hex.pattern'}\n"; 412 | print "SIZE_COM=$$v{'recipe.size.pattern'}\n"; 413 | my $$flash_size = sprintf("0x%X", hex($$v{'build.spiffs_end'})-hex($$v{'build.spiffs_start'})); 414 | print "MKSPIFFS_COM=$$v{'tools.mkspiffs.path'}/$$v{'tools.mkspiffs.cmd'} -b $$v{'build.spiffs_blocksize'} -s $$flash_size -c \$$(FS_DIR) \$$(FS_IMAGE)\n"; 415 | print "UPLOAD_COM=$$v{'tools.esptool.upload.pattern'}\n"; 416 | my $$fs_upload_com = $$v{'tools.esptool.upload.pattern'}; 417 | $$fs_upload_com =~ s/(.+ -ca) .+/$$1 $$v{'build.spiffs_start'} -cf \$$(FS_IMAGE)/; 418 | print "FS_UPLOAD_COM=$$fs_upload_com\n"; 419 | my $$val = $$v{'recipe.hooks.core.prebuild.1.pattern'}; 420 | $$val =~ s/bash -c "(.+)"/$$1/; 421 | $$val =~ s/(#define .+0x)(\`)/"\\$$1\"$$2/; 422 | $$val =~ s/(\\)//; 423 | print "PREBUILD_COM=$$val\n"; 424 | print "MEM_FLASH=$$v{'recipe.size.regex'}\n"; 425 | print "MEM_RAM=$$v{'recipe.size.regex.data'}\n"; 426 | print "FLASH_INFO=$$v{'menu.FlashSize.' . $$flashSize}\n" 427 | endef 428 | export PARSE_ARDUINO 429 | 430 | # Convert memory information 431 | define MEM_USAGE 432 | $$fp = shift; 433 | $$rp = shift; 434 | while (<>) { 435 | $$r += $$1 if /$$rp/; 436 | $$f += $$1 if /$$fp/; 437 | } 438 | print "\nMemory usage\n"; 439 | print sprintf(" %-6s %6d bytes\n" x 2 ."\n", "Ram:", $$r, "Flash:", $$f); 440 | endef 441 | export MEM_USAGE 442 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/README.md: -------------------------------------------------------------------------------- 1 | # ESP8266MeshIRRemote 2 | 3 | This is an example of an IR Blaster controlled via MQTT commands 4 | 5 | The blaster uses Pronto codes (though it should be easy to add support for all protocols handled by the IRRemote library). 6 | The Pronto protocol is very flexible, and should be able to handle virtually all IR codes. 7 | 8 | Codes can be saved in a file on the device to make it easy to send frequently used codes 9 | 10 | ## Hardware 11 | 12 | The IRBlaster directory contains the Eagle libraries for the IRBlaster used in this example. 13 | 14 | The board is quite basic. It uses an ESP01 module along with a 2n7000 to drive an IR LED. A LM1117-3.3 module is connected 15 | to a mini-usb to provide power. 16 | 17 | This was built before Eagle 18 | was moved to a subscription plan. I have since moved to using KiCad, but there was no reason to redesign the schematics. 19 | 20 | A PDF of the schematic is provided. Boards can be ordered from OshPark here: 21 | Order from OSH Park 22 | 23 | ## MQTT Commands 24 | 25 | | Topic | Message | Description | 26 | |-------|---------|-------------| 27 | | \/send | code=\ | send specified code one time | 28 | | \/send | repeat=5,code=\ | send specified code 5 times | 29 | | \/send | repeat=5,code=\,repeat=3,pronto=\ | send code1 5 times followed by sending code2 3 times | 30 | | \/send | repeat=5,file=\,file=\,... | send pronto code previously saved in 'filename1' 5 times, followed by the contents of 'filename2' | 31 | | \/list | "" | returns a list of all saved files | 32 | | \/debug | \<1|0> | enable/disable debugging messages over MQTT | 33 | | \/save/\ | code=\ | save specified pronto code to 'filename' on esp8266 device | 34 | | \/read/\ | "" | return contents of 'flename' via MQTT | 35 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/config.mk: -------------------------------------------------------------------------------- 1 | FLASH_DEF = 1M256 2 | USER_LIBS = ${HOME}/Arduino/libraries/ 3 | CPP_EXTRA = -Wall 4 | BUILD_EXTRA_FLAGS = "-DMQTT_MAX_PACKET_SIZE=1152" 5 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/lib/IRremoteESP8266/Contributors.md: -------------------------------------------------------------------------------- 1 | ## Contributors of this project 2 | - [Mark Szabo](https://github.com/markszabo/) : IR sending on ESP8266 3 | - [Sébastien Warin](https://github.com/sebastienwarin/) (http://sebastien.warin.fr) : IR receiving on ESP8266 4 | 5 | ## Contributors of the original project (https://github.com/shirriff/Arduino-IRremote/) 6 | These are the active contributors of this project that you may contact if there is anything you need help with or if you have suggestions. 7 | 8 | - [z3t0](https://github.com/z3t0) : Active Contributor and currently also the main contributor. 9 | * Email: zetoslab@gmail.com 10 | * Skype: polarised16 11 | - [shirriff](https://github.com/shirriff) : Owner of repository and creator of library. 12 | - [Informatic](https://github.com/Informatic) : Active contributor 13 | - [fmeschia](https://github.com/fmeschia) : Active contributor 14 | - [PaulStoffregen](https://github.com/paulstroffregen) : Active contributor 15 | - [crash7](https://github.com/crash7) : Active contributor 16 | - [Neco777](https://github.com/neco777) : Active contributor 17 | 18 | Note: This list is being updated constantly so please let [z3t0](https://github.com/z3t0) know if you have been missed. 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/lib/IRremoteESP8266/IRremoteESP8266.h: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | * IRremote for ESP8266 3 | * 4 | * Based on the IRremote library for Arduino by Ken Shirriff 5 | * Version 0.11 August, 2009 6 | * Copyright 2009 Ken Shirriff 7 | * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html 8 | * 9 | * Edited by Mitra to add new controller SANYO 10 | * 11 | * Interrupt code based on NECIRrcv by Joe Knapp 12 | * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 13 | * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ 14 | * 15 | * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) 16 | * LG added by Darryl Smith (based on the JVC protocol) 17 | * Whynter A/C ARC-110WD added by Francesco Meschia 18 | * 19 | * Updated by markszabo (https://github.com/markszabo/IRremoteESP8266) for sending IR code on ESP8266 20 | * Updated by Sebastien Warin (http://sebastien.warin.fr) for receiving IR code on ESP8266 21 | * 22 | * GPL license, all text above must be included in any redistribution 23 | ****************************************************/ 24 | 25 | #ifndef IRremote_h 26 | #define IRremote_h 27 | 28 | // The following are compile-time library options. 29 | // If you change them, recompile the library. 30 | // If DEBUG is defined, a lot of debugging output will be printed during decoding. 31 | // TEST must be defined for the IRtest unittests to work. It will make some 32 | // methods virtual, which will be slightly slower, which is why it is optional. 33 | //#define DEBUG 34 | //#define TEST 35 | 36 | enum decode_type_t { 37 | NEC = 1, 38 | SONY = 2, 39 | RC5 = 3, 40 | RC6 = 4, 41 | DISH = 5, 42 | SHARP = 6, 43 | PANASONIC = 7, 44 | JVC = 8, 45 | SANYO = 9, 46 | MITSUBISHI = 10, 47 | SAMSUNG = 11, 48 | LG = 12, 49 | WHYNTER = 13, 50 | AIWA_RC_T501 = 14, 51 | 52 | UNKNOWN = -1 53 | }; 54 | 55 | // Results returned from the decoder 56 | class decode_results { 57 | public: 58 | int decode_type; // NEC, SONY, RC5, UNKNOWN 59 | union { // This is used for decoding Panasonic and Sharp data 60 | unsigned int panasonicAddress; 61 | unsigned int sharpAddress; 62 | }; 63 | unsigned long value; // Decoded value 64 | int bits; // Number of bits in decoded value 65 | volatile unsigned int *rawbuf; // Raw intervals in .5 us ticks 66 | int rawlen; // Number of records in rawbuf. 67 | }; 68 | 69 | // Values for decode_type 70 | #define NEC 1 71 | #define SONY 2 72 | #define RC5 3 73 | #define RC6 4 74 | #define DISH 5 75 | #define SHARP 6 76 | #define PANASONIC 7 77 | #define JVC 8 78 | #define SANYO 9 79 | #define MITSUBISHI 10 80 | #define SAMSUNG 11 81 | #define LG 12 82 | #define WHYNTER 13 83 | #define UNKNOWN -1 84 | 85 | // Decoded value for NEC when a repeat code is received 86 | #define REPEAT 0xffffffff 87 | 88 | // main class for receiving IR 89 | class IRrecv 90 | { 91 | public: 92 | IRrecv(int recvpin); 93 | int decode(decode_results *results); 94 | void enableIRIn(); 95 | void disableIRIn(); 96 | void resume(); 97 | private: 98 | // These are called by decode 99 | int getRClevel(decode_results *results, int *offset, int *used, int t1); 100 | long decodeNEC(decode_results *results); 101 | long decodeSony(decode_results *results); 102 | long decodeSanyo(decode_results *results); 103 | long decodeMitsubishi(decode_results *results); 104 | long decodeRC5(decode_results *results); 105 | long decodeRC6(decode_results *results); 106 | long decodePanasonic(decode_results *results); 107 | long decodeLG(decode_results *results); 108 | long decodeJVC(decode_results *results); 109 | long decodeSAMSUNG(decode_results *results); 110 | long decodeWhynter(decode_results *results); 111 | long decodeHash(decode_results *results); 112 | int compare(unsigned int oldval, unsigned int newval); 113 | }; 114 | 115 | // Only used for testing; can remove virtual for shorter code 116 | #ifdef TEST 117 | #define VIRTUAL virtual 118 | #else 119 | #define VIRTUAL 120 | #endif 121 | class IRsend 122 | { 123 | public: 124 | IRsend(int IRsendPin); 125 | void begin(); 126 | void sendWhynter(unsigned long data, int nbits); 127 | void sendNEC(unsigned long data, int nbits); 128 | void sendLG(unsigned long data, int nbits); 129 | void sendSony(unsigned long data, int nbits); 130 | // Neither Sanyo nor Mitsubishi send is implemented yet 131 | // void sendSanyo(unsigned long data, int nbits); 132 | // void sendMitsubishi(unsigned long data, int nbits); 133 | void sendRaw(unsigned int buf[], int len, int hz); 134 | void sendRC5(unsigned long data, int nbits); 135 | void sendRC6(unsigned long data, int nbits); 136 | void sendDISH(unsigned long data, int nbits); 137 | void sendSharp(unsigned int address, unsigned int command); 138 | void sendSharpRaw(unsigned long data, int nbits); 139 | void sendPanasonic(unsigned int address, unsigned long data); 140 | void sendJVC(unsigned long data, int nbits, int repeat); // *Note instead of sending the REPEAT constant if you want the JVC repeat signal sent, send the original code value and change the repeat argument from 0 to 1. JVC protocol repeats by skipping the header NOT by sending a separate code value like NEC does. 141 | void sendSAMSUNG(unsigned long data, int nbits); 142 | void sendDenon (unsigned long data, int nbits); 143 | bool sendPronto (const char* s, bool repeat, bool fallback); 144 | void enableIROut(int khz); 145 | VIRTUAL void mark(int usec); 146 | VIRTUAL void space(int usec); 147 | private: 148 | int halfPeriodicTime; 149 | int IRpin; 150 | } ; 151 | 152 | // Some useful constants 153 | #define USECPERTICK 50 // microseconds per clock interrupt tick 154 | #define RAWBUF 100 // Length of raw duration buffer 155 | 156 | // Marks tend to be 100us too long, and spaces 100us too short 157 | // when received due to sensor lag. 158 | #define MARK_EXCESS 100 159 | 160 | #endif 161 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/lib/IRremoteESP8266/IRremoteInt.h: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | * IRremote for ESP8266 3 | * 4 | * Based on the IRremote library for Arduino by Ken Shirriff 5 | * Version 0.11 August, 2009 6 | * Copyright 2009 Ken Shirriff 7 | * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html 8 | * 9 | * Modified by Paul Stoffregen to support other boards and timers 10 | * 11 | * Interrupt code based on NECIRrcv by Joe Knapp 12 | * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 13 | * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ 14 | * 15 | * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) 16 | * Whynter A/C ARC-110WD added by Francesco Meschia 17 | * 18 | * 09/23/2015 : Samsung pulse parameters updated by Sebastien Warin to be compatible with EUxxD6200 19 | * 20 | * GPL license, all text above must be included in any redistribution 21 | ****************************************************/ 22 | 23 | #ifndef IRremoteint_h 24 | #define IRremoteint_h 25 | 26 | #if defined(ARDUINO) && ARDUINO >= 100 27 | #include 28 | #else 29 | #include 30 | #endif 31 | 32 | // Pulse parms are *50-100 for the Mark and *50+100 for the space 33 | // First MARK is the one after the long gap 34 | // pulse parameters in usec 35 | #define WHYNTER_HDR_MARK 2850 36 | #define WHYNTER_HDR_SPACE 2850 37 | #define WHYNTER_BIT_MARK 750 38 | #define WHYNTER_ONE_MARK 750 39 | #define WHYNTER_ONE_SPACE 2150 40 | #define WHYNTER_ZERO_MARK 750 41 | #define WHYNTER_ZERO_SPACE 750 42 | 43 | #define NEC_HDR_MARK 9000 44 | #define NEC_HDR_SPACE 4500 45 | #define NEC_BIT_MARK 560 46 | #define NEC_ONE_SPACE 1690 47 | #define NEC_ZERO_SPACE 560 48 | #define NEC_RPT_SPACE 2250 49 | 50 | #define SONY_HDR_MARK 2400 51 | #define SONY_HDR_SPACE 600 52 | #define SONY_ONE_MARK 1200 53 | #define SONY_ZERO_MARK 600 54 | #define SONY_RPT_LENGTH 45000 55 | #define SONY_DOUBLE_SPACE_USECS 500 // usually ssee 713 - not using ticks as get number wrapround 56 | 57 | // SA 8650B 58 | #define SANYO_HDR_MARK 3500 // seen range 3500 59 | #define SANYO_HDR_SPACE 950 // seen 950 60 | #define SANYO_ONE_MARK 2400 // seen 2400 61 | #define SANYO_ZERO_MARK 700 // seen 700 62 | #define SANYO_DOUBLE_SPACE_USECS 800 // usually ssee 713 - not using ticks as get number wrapround 63 | #define SANYO_RPT_LENGTH 45000 64 | 65 | // Mitsubishi RM 75501 66 | // 14200 7 41 7 42 7 42 7 17 7 17 7 18 7 41 7 18 7 17 7 17 7 18 7 41 8 17 7 17 7 18 7 17 7 67 | 68 | // #define MITSUBISHI_HDR_MARK 250 // seen range 3500 69 | #define MITSUBISHI_HDR_SPACE 350 // 7*50+100 70 | #define MITSUBISHI_ONE_MARK 1950 // 41*50-100 71 | #define MITSUBISHI_ZERO_MARK 750 // 17*50-100 72 | // #define MITSUBISHI_DOUBLE_SPACE_USECS 800 // usually ssee 713 - not using ticks as get number wrapround 73 | // #define MITSUBISHI_RPT_LENGTH 45000 74 | 75 | 76 | #define RC5_T1 889 77 | #define RC5_RPT_LENGTH 46000 78 | 79 | #define RC6_HDR_MARK 2666 80 | #define RC6_HDR_SPACE 889 81 | #define RC6_T1 444 82 | #define RC6_RPT_LENGTH 46000 83 | 84 | #define SHARP_BIT_MARK 245 85 | #define SHARP_ONE_SPACE 1805 86 | #define SHARP_ZERO_SPACE 795 87 | #define SHARP_GAP 600000 88 | #define SHARP_TOGGLE_MASK 0x3FF 89 | #define SHARP_RPT_SPACE 3000 90 | 91 | #define DISH_HDR_MARK 400 92 | #define DISH_HDR_SPACE 6100 93 | #define DISH_BIT_MARK 400 94 | #define DISH_ONE_SPACE 1700 95 | #define DISH_ZERO_SPACE 2800 96 | #define DISH_RPT_SPACE 6200 97 | #define DISH_TOP_BIT 0x8000 98 | 99 | #define PANASONIC_HDR_MARK 3502 100 | #define PANASONIC_HDR_SPACE 1750 101 | #define PANASONIC_BIT_MARK 502 102 | #define PANASONIC_ONE_SPACE 1244 103 | #define PANASONIC_ZERO_SPACE 400 104 | 105 | #define JVC_HDR_MARK 8000 106 | #define JVC_HDR_SPACE 4000 107 | #define JVC_BIT_MARK 600 108 | #define JVC_ONE_SPACE 1600 109 | #define JVC_ZERO_SPACE 550 110 | #define JVC_RPT_LENGTH 60000 111 | 112 | #define LG_HDR_MARK 8000 113 | #define LG_HDR_SPACE 4000 114 | #define LG_BIT_MARK 600 115 | #define LG_ONE_SPACE 1600 116 | #define LG_ZERO_SPACE 550 117 | #define LG_RPT_LENGTH 60000 118 | 119 | /* 120 | #define SAMSUNG_HDR_MARK 5000 121 | #define SAMSUNG_HDR_SPACE 5000 122 | #define SAMSUNG_BIT_MARK 560 123 | #define SAMSUNG_ONE_SPACE 1600 124 | #define SAMSUNG_ZERO_SPACE 560 125 | #define SAMSUNG_RPT_SPACE 2250 126 | */ 127 | 128 | // Update by Sebastien Warin for my EU46D6200 129 | #define SAMSUNG_HDR_MARK 4500 130 | #define SAMSUNG_HDR_SPACE 4500 131 | #define SAMSUNG_BIT_MARK 590 132 | #define SAMSUNG_ONE_SPACE 1690 133 | #define SAMSUNG_ZERO_SPACE 590 134 | #define SAMSUNG_RPT_SPACE 2250 135 | 136 | #define SHARP_BITS 15 137 | #define DISH_BITS 16 138 | 139 | #define DENON_BITS 14 // The number of bits in the command 140 | 141 | #define DENON_HDR_MARK 300 // The length of the Header:Mark 142 | #define DENON_HDR_SPACE 750 // The lenght of the Header:Space 143 | 144 | #define DENON_BIT_MARK 300 // The length of a Bit:Mark 145 | #define DENON_ONE_SPACE 1800 // The length of a Bit:Space for 1's 146 | #define DENON_ZERO_SPACE 750 // The length of a Bit:Space for 0's 147 | 148 | #define TOLERANCE 25 // percent tolerance in measurements 149 | #define LTOL (1.0 - TOLERANCE/100.) 150 | #define UTOL (1.0 + TOLERANCE/100.) 151 | 152 | #define _GAP 5000 // Minimum map between transmissions 153 | #define GAP_TICKS (_GAP/USECPERTICK) 154 | 155 | #define TICKS_LOW(us) (int) (((us)*LTOL/USECPERTICK)) 156 | #define TICKS_HIGH(us) (int) (((us)*UTOL/USECPERTICK + 1)) 157 | 158 | // receiver states 159 | #define STATE_IDLE 2 160 | #define STATE_MARK 3 161 | #define STATE_SPACE 4 162 | #define STATE_STOP 5 163 | 164 | #define ERR 0 165 | #define DECODED 1 166 | 167 | // information for the interrupt handler 168 | typedef struct { 169 | uint8_t recvpin; // pin for IR data from detector 170 | uint8_t rcvstate; // state machine 171 | unsigned int timer; // state timer, counts 50uS ticks. 172 | unsigned int rawbuf[RAWBUF]; // raw data 173 | uint8_t rawlen; // counter of entries in rawbuf 174 | } 175 | irparams_t; 176 | 177 | // Defined in IRremote.cpp 178 | extern volatile irparams_t irparams; 179 | 180 | // IR detector output is active low 181 | #define MARK 0 182 | #define SPACE 1 183 | 184 | #define TOPBIT 0x80000000 185 | 186 | #define NEC_BITS 32 187 | #define SONY_BITS 12 188 | #define SANYO_BITS 12 189 | #define MITSUBISHI_BITS 16 190 | #define MIN_RC5_SAMPLES 11 191 | #define MIN_RC6_SAMPLES 1 192 | #define PANASONIC_BITS 48 193 | #define JVC_BITS 16 194 | #define LG_BITS 28 195 | #define SAMSUNG_BITS 32 196 | #define WHYNTER_BITS 32 197 | 198 | #endif 199 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/lib/IRremoteESP8266/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | GNU LESSER GENERAL PUBLIC LICENSE 3 | Version 2.1, February 1999 4 | 5 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 6 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 7 | Everyone is permitted to copy and distribute verbatim copies 8 | of this license document, but changing it is not allowed. 9 | 10 | [This is the first released version of the Lesser GPL. It also counts 11 | as the successor of the GNU Library Public License, version 2, hence 12 | the version number 2.1.] 13 | 14 | Preamble 15 | 16 | The licenses for most software are designed to take away your 17 | freedom to share and change it. By contrast, the GNU General Public 18 | Licenses are intended to guarantee your freedom to share and change 19 | free software--to make sure the software is free for all its users. 20 | 21 | This license, the Lesser General Public License, applies to some 22 | specially designated software packages--typically libraries--of the 23 | Free Software Foundation and other authors who decide to use it. You 24 | can use it too, but we suggest you first think carefully about whether 25 | this license or the ordinary General Public License is the better 26 | strategy to use in any particular case, based on the explanations below. 27 | 28 | When we speak of free software, we are referring to freedom of use, 29 | not price. Our General Public Licenses are designed to make sure that 30 | you have the freedom to distribute copies of free software (and charge 31 | for this service if you wish); that you receive source code or can get 32 | it if you want it; that you can change the software and use pieces of 33 | it in new free programs; and that you are informed that you can do 34 | these things. 35 | 36 | To protect your rights, we need to make restrictions that forbid 37 | distributors to deny you these rights or to ask you to surrender these 38 | rights. These restrictions translate to certain responsibilities for 39 | you if you distribute copies of the library or if you modify it. 40 | 41 | For example, if you distribute copies of the library, whether gratis 42 | or for a fee, you must give the recipients all the rights that we gave 43 | you. You must make sure that they, too, receive or can get the source 44 | code. If you link other code with the library, you must provide 45 | complete object files to the recipients, so that they can relink them 46 | with the library after making changes to the library and recompiling 47 | it. And you must show them these terms so they know their rights. 48 | 49 | We protect your rights with a two-step method: (1) we copyright the 50 | library, and (2) we offer you this license, which gives you legal 51 | permission to copy, distribute and/or modify the library. 52 | 53 | To protect each distributor, we want to make it very clear that 54 | there is no warranty for the free library. Also, if the library is 55 | modified by someone else and passed on, the recipients should know 56 | that what they have is not the original version, so that the original 57 | author's reputation will not be affected by problems that might be 58 | introduced by others. 59 | 60 | Finally, software patents pose a constant threat to the existence of 61 | any free program. We wish to make sure that a company cannot 62 | effectively restrict the users of a free program by obtaining a 63 | restrictive license from a patent holder. Therefore, we insist that 64 | any patent license obtained for a version of the library must be 65 | consistent with the full freedom of use specified in this license. 66 | 67 | Most GNU software, including some libraries, is covered by the 68 | ordinary GNU General Public License. This license, the GNU Lesser 69 | General Public License, applies to certain designated libraries, and 70 | is quite different from the ordinary General Public License. We use 71 | this license for certain libraries in order to permit linking those 72 | libraries into non-free programs. 73 | 74 | When a program is linked with a library, whether statically or using 75 | a shared library, the combination of the two is legally speaking a 76 | combined work, a derivative of the original library. The ordinary 77 | General Public License therefore permits such linking only if the 78 | entire combination fits its criteria of freedom. The Lesser General 79 | Public License permits more lax criteria for linking other code with 80 | the library. 81 | 82 | We call this license the "Lesser" General Public License because it 83 | does Less to protect the user's freedom than the ordinary General 84 | Public License. It also provides other free software developers Less 85 | of an advantage over competing non-free programs. These disadvantages 86 | are the reason we use the ordinary General Public License for many 87 | libraries. However, the Lesser license provides advantages in certain 88 | special circumstances. 89 | 90 | For example, on rare occasions, there may be a special need to 91 | encourage the widest possible use of a certain library, so that it becomes 92 | a de-facto standard. To achieve this, non-free programs must be 93 | allowed to use the library. A more frequent case is that a free 94 | library does the same job as widely used non-free libraries. In this 95 | case, there is little to gain by limiting the free library to free 96 | software only, so we use the Lesser General Public License. 97 | 98 | In other cases, permission to use a particular library in non-free 99 | programs enables a greater number of people to use a large body of 100 | free software. For example, permission to use the GNU C Library in 101 | non-free programs enables many more people to use the whole GNU 102 | operating system, as well as its variant, the GNU/Linux operating 103 | system. 104 | 105 | Although the Lesser General Public License is Less protective of the 106 | users' freedom, it does ensure that the user of a program that is 107 | linked with the Library has the freedom and the wherewithal to run 108 | that program using a modified version of the Library. 109 | 110 | The precise terms and conditions for copying, distribution and 111 | modification follow. Pay close attention to the difference between a 112 | "work based on the library" and a "work that uses the library". The 113 | former contains code derived from the library, whereas the latter must 114 | be combined with the library in order to run. 115 | 116 | GNU LESSER GENERAL PUBLIC LICENSE 117 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 118 | 119 | 0. This License Agreement applies to any software library or other 120 | program which contains a notice placed by the copyright holder or 121 | other authorized party saying it may be distributed under the terms of 122 | this Lesser General Public License (also called "this License"). 123 | Each licensee is addressed as "you". 124 | 125 | A "library" means a collection of software functions and/or data 126 | prepared so as to be conveniently linked with application programs 127 | (which use some of those functions and data) to form executables. 128 | 129 | The "Library", below, refers to any such software library or work 130 | which has been distributed under these terms. A "work based on the 131 | Library" means either the Library or any derivative work under 132 | copyright law: that is to say, a work containing the Library or a 133 | portion of it, either verbatim or with modifications and/or translated 134 | straightforwardly into another language. (Hereinafter, translation is 135 | included without limitation in the term "modification".) 136 | 137 | "Source code" for a work means the preferred form of the work for 138 | making modifications to it. For a library, complete source code means 139 | all the source code for all modules it contains, plus any associated 140 | interface definition files, plus the scripts used to control compilation 141 | and installation of the library. 142 | 143 | Activities other than copying, distribution and modification are not 144 | covered by this License; they are outside its scope. The act of 145 | running a program using the Library is not restricted, and output from 146 | such a program is covered only if its contents constitute a work based 147 | on the Library (independent of the use of the Library in a tool for 148 | writing it). Whether that is true depends on what the Library does 149 | and what the program that uses the Library does. 150 | 151 | 1. You may copy and distribute verbatim copies of the Library's 152 | complete source code as you receive it, in any medium, provided that 153 | you conspicuously and appropriately publish on each copy an 154 | appropriate copyright notice and disclaimer of warranty; keep intact 155 | all the notices that refer to this License and to the absence of any 156 | warranty; and distribute a copy of this License along with the 157 | Library. 158 | 159 | You may charge a fee for the physical act of transferring a copy, 160 | and you may at your option offer warranty protection in exchange for a 161 | fee. 162 | 163 | 2. You may modify your copy or copies of the Library or any portion 164 | of it, thus forming a work based on the Library, and copy and 165 | distribute such modifications or work under the terms of Section 1 166 | above, provided that you also meet all of these conditions: 167 | 168 | a) The modified work must itself be a software library. 169 | 170 | b) You must cause the files modified to carry prominent notices 171 | stating that you changed the files and the date of any change. 172 | 173 | c) You must cause the whole of the work to be licensed at no 174 | charge to all third parties under the terms of this License. 175 | 176 | d) If a facility in the modified Library refers to a function or a 177 | table of data to be supplied by an application program that uses 178 | the facility, other than as an argument passed when the facility 179 | is invoked, then you must make a good faith effort to ensure that, 180 | in the event an application does not supply such function or 181 | table, the facility still operates, and performs whatever part of 182 | its purpose remains meaningful. 183 | 184 | (For example, a function in a library to compute square roots has 185 | a purpose that is entirely well-defined independent of the 186 | application. Therefore, Subsection 2d requires that any 187 | application-supplied function or table used by this function must 188 | be optional: if the application does not supply it, the square 189 | root function must still compute square roots.) 190 | 191 | These requirements apply to the modified work as a whole. If 192 | identifiable sections of that work are not derived from the Library, 193 | and can be reasonably considered independent and separate works in 194 | themselves, then this License, and its terms, do not apply to those 195 | sections when you distribute them as separate works. But when you 196 | distribute the same sections as part of a whole which is a work based 197 | on the Library, the distribution of the whole must be on the terms of 198 | this License, whose permissions for other licensees extend to the 199 | entire whole, and thus to each and every part regardless of who wrote 200 | it. 201 | 202 | Thus, it is not the intent of this section to claim rights or contest 203 | your rights to work written entirely by you; rather, the intent is to 204 | exercise the right to control the distribution of derivative or 205 | collective works based on the Library. 206 | 207 | In addition, mere aggregation of another work not based on the Library 208 | with the Library (or with a work based on the Library) on a volume of 209 | a storage or distribution medium does not bring the other work under 210 | the scope of this License. 211 | 212 | 3. You may opt to apply the terms of the ordinary GNU General Public 213 | License instead of this License to a given copy of the Library. To do 214 | this, you must alter all the notices that refer to this License, so 215 | that they refer to the ordinary GNU General Public License, version 2, 216 | instead of to this License. (If a newer version than version 2 of the 217 | ordinary GNU General Public License has appeared, then you can specify 218 | that version instead if you wish.) Do not make any other change in 219 | these notices. 220 | 221 | Once this change is made in a given copy, it is irreversible for 222 | that copy, so the ordinary GNU General Public License applies to all 223 | subsequent copies and derivative works made from that copy. 224 | 225 | This option is useful when you wish to copy part of the code of 226 | the Library into a program that is not a library. 227 | 228 | 4. You may copy and distribute the Library (or a portion or 229 | derivative of it, under Section 2) in object code or executable form 230 | under the terms of Sections 1 and 2 above provided that you accompany 231 | it with the complete corresponding machine-readable source code, which 232 | must be distributed under the terms of Sections 1 and 2 above on a 233 | medium customarily used for software interchange. 234 | 235 | If distribution of object code is made by offering access to copy 236 | from a designated place, then offering equivalent access to copy the 237 | source code from the same place satisfies the requirement to 238 | distribute the source code, even though third parties are not 239 | compelled to copy the source along with the object code. 240 | 241 | 5. A program that contains no derivative of any portion of the 242 | Library, but is designed to work with the Library by being compiled or 243 | linked with it, is called a "work that uses the Library". Such a 244 | work, in isolation, is not a derivative work of the Library, and 245 | therefore falls outside the scope of this License. 246 | 247 | However, linking a "work that uses the Library" with the Library 248 | creates an executable that is a derivative of the Library (because it 249 | contains portions of the Library), rather than a "work that uses the 250 | library". The executable is therefore covered by this License. 251 | Section 6 states terms for distribution of such executables. 252 | 253 | When a "work that uses the Library" uses material from a header file 254 | that is part of the Library, the object code for the work may be a 255 | derivative work of the Library even though the source code is not. 256 | Whether this is true is especially significant if the work can be 257 | linked without the Library, or if the work is itself a library. The 258 | threshold for this to be true is not precisely defined by law. 259 | 260 | If such an object file uses only numerical parameters, data 261 | structure layouts and accessors, and small macros and small inline 262 | functions (ten lines or less in length), then the use of the object 263 | file is unrestricted, regardless of whether it is legally a derivative 264 | work. (Executables containing this object code plus portions of the 265 | Library will still fall under Section 6.) 266 | 267 | Otherwise, if the work is a derivative of the Library, you may 268 | distribute the object code for the work under the terms of Section 6. 269 | Any executables containing that work also fall under Section 6, 270 | whether or not they are linked directly with the Library itself. 271 | 272 | 6. As an exception to the Sections above, you may also combine or 273 | link a "work that uses the Library" with the Library to produce a 274 | work containing portions of the Library, and distribute that work 275 | under terms of your choice, provided that the terms permit 276 | modification of the work for the customer's own use and reverse 277 | engineering for debugging such modifications. 278 | 279 | You must give prominent notice with each copy of the work that the 280 | Library is used in it and that the Library and its use are covered by 281 | this License. You must supply a copy of this License. If the work 282 | during execution displays copyright notices, you must include the 283 | copyright notice for the Library among them, as well as a reference 284 | directing the user to the copy of this License. Also, you must do one 285 | of these things: 286 | 287 | a) Accompany the work with the complete corresponding 288 | machine-readable source code for the Library including whatever 289 | changes were used in the work (which must be distributed under 290 | Sections 1 and 2 above); and, if the work is an executable linked 291 | with the Library, with the complete machine-readable "work that 292 | uses the Library", as object code and/or source code, so that the 293 | user can modify the Library and then relink to produce a modified 294 | executable containing the modified Library. (It is understood 295 | that the user who changes the contents of definitions files in the 296 | Library will not necessarily be able to recompile the application 297 | to use the modified definitions.) 298 | 299 | b) Use a suitable shared library mechanism for linking with the 300 | Library. A suitable mechanism is one that (1) uses at run time a 301 | copy of the library already present on the user's computer system, 302 | rather than copying library functions into the executable, and (2) 303 | will operate properly with a modified version of the library, if 304 | the user installs one, as long as the modified version is 305 | interface-compatible with the version that the work was made with. 306 | 307 | c) Accompany the work with a written offer, valid for at 308 | least three years, to give the same user the materials 309 | specified in Subsection 6a, above, for a charge no more 310 | than the cost of performing this distribution. 311 | 312 | d) If distribution of the work is made by offering access to copy 313 | from a designated place, offer equivalent access to copy the above 314 | specified materials from the same place. 315 | 316 | e) Verify that the user has already received a copy of these 317 | materials or that you have already sent this user a copy. 318 | 319 | For an executable, the required form of the "work that uses the 320 | Library" must include any data and utility programs needed for 321 | reproducing the executable from it. However, as a special exception, 322 | the materials to be distributed need not include anything that is 323 | normally distributed (in either source or binary form) with the major 324 | components (compiler, kernel, and so on) of the operating system on 325 | which the executable runs, unless that component itself accompanies 326 | the executable. 327 | 328 | It may happen that this requirement contradicts the license 329 | restrictions of other proprietary libraries that do not normally 330 | accompany the operating system. Such a contradiction means you cannot 331 | use both them and the Library together in an executable that you 332 | distribute. 333 | 334 | 7. You may place library facilities that are a work based on the 335 | Library side-by-side in a single library together with other library 336 | facilities not covered by this License, and distribute such a combined 337 | library, provided that the separate distribution of the work based on 338 | the Library and of the other library facilities is otherwise 339 | permitted, and provided that you do these two things: 340 | 341 | a) Accompany the combined library with a copy of the same work 342 | based on the Library, uncombined with any other library 343 | facilities. This must be distributed under the terms of the 344 | Sections above. 345 | 346 | b) Give prominent notice with the combined library of the fact 347 | that part of it is a work based on the Library, and explaining 348 | where to find the accompanying uncombined form of the same work. 349 | 350 | 8. You may not copy, modify, sublicense, link with, or distribute 351 | the Library except as expressly provided under this License. Any 352 | attempt otherwise to copy, modify, sublicense, link with, or 353 | distribute the Library is void, and will automatically terminate your 354 | rights under this License. However, parties who have received copies, 355 | or rights, from you under this License will not have their licenses 356 | terminated so long as such parties remain in full compliance. 357 | 358 | 9. You are not required to accept this License, since you have not 359 | signed it. However, nothing else grants you permission to modify or 360 | distribute the Library or its derivative works. These actions are 361 | prohibited by law if you do not accept this License. Therefore, by 362 | modifying or distributing the Library (or any work based on the 363 | Library), you indicate your acceptance of this License to do so, and 364 | all its terms and conditions for copying, distributing or modifying 365 | the Library or works based on it. 366 | 367 | 10. Each time you redistribute the Library (or any work based on the 368 | Library), the recipient automatically receives a license from the 369 | original licensor to copy, distribute, link with or modify the Library 370 | subject to these terms and conditions. You may not impose any further 371 | restrictions on the recipients' exercise of the rights granted herein. 372 | You are not responsible for enforcing compliance by third parties with 373 | this License. 374 | 375 | 11. If, as a consequence of a court judgment or allegation of patent 376 | infringement or for any other reason (not limited to patent issues), 377 | conditions are imposed on you (whether by court order, agreement or 378 | otherwise) that contradict the conditions of this License, they do not 379 | excuse you from the conditions of this License. If you cannot 380 | distribute so as to satisfy simultaneously your obligations under this 381 | License and any other pertinent obligations, then as a consequence you 382 | may not distribute the Library at all. For example, if a patent 383 | license would not permit royalty-free redistribution of the Library by 384 | all those who receive copies directly or indirectly through you, then 385 | the only way you could satisfy both it and this License would be to 386 | refrain entirely from distribution of the Library. 387 | 388 | If any portion of this section is held invalid or unenforceable under any 389 | particular circumstance, the balance of the section is intended to apply, 390 | and the section as a whole is intended to apply in other circumstances. 391 | 392 | It is not the purpose of this section to induce you to infringe any 393 | patents or other property right claims or to contest validity of any 394 | such claims; this section has the sole purpose of protecting the 395 | integrity of the free software distribution system which is 396 | implemented by public license practices. Many people have made 397 | generous contributions to the wide range of software distributed 398 | through that system in reliance on consistent application of that 399 | system; it is up to the author/donor to decide if he or she is willing 400 | to distribute software through any other system and a licensee cannot 401 | impose that choice. 402 | 403 | This section is intended to make thoroughly clear what is believed to 404 | be a consequence of the rest of this License. 405 | 406 | 12. If the distribution and/or use of the Library is restricted in 407 | certain countries either by patents or by copyrighted interfaces, the 408 | original copyright holder who places the Library under this License may add 409 | an explicit geographical distribution limitation excluding those countries, 410 | so that distribution is permitted only in or among countries not thus 411 | excluded. In such case, this License incorporates the limitation as if 412 | written in the body of this License. 413 | 414 | 13. The Free Software Foundation may publish revised and/or new 415 | versions of the Lesser General Public License from time to time. 416 | Such new versions will be similar in spirit to the present version, 417 | but may differ in detail to address new problems or concerns. 418 | 419 | Each version is given a distinguishing version number. If the Library 420 | specifies a version number of this License which applies to it and 421 | "any later version", you have the option of following the terms and 422 | conditions either of that version or of any later version published by 423 | the Free Software Foundation. If the Library does not specify a 424 | license version number, you may choose any version ever published by 425 | the Free Software Foundation. 426 | 427 | 14. If you wish to incorporate parts of the Library into other free 428 | programs whose distribution conditions are incompatible with these, 429 | write to the author to ask for permission. For software which is 430 | copyrighted by the Free Software Foundation, write to the Free 431 | Software Foundation; we sometimes make exceptions for this. Our 432 | decision will be guided by the two goals of preserving the free status 433 | of all derivatives of our free software and of promoting the sharing 434 | and reuse of software generally. 435 | 436 | NO WARRANTY 437 | 438 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 439 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 440 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 441 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 442 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 443 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 444 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 445 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 446 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 447 | 448 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 449 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 450 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 451 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 452 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 453 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 454 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 455 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 456 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 457 | DAMAGES. 458 | 459 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/lib/IRremoteESP8266/README.md: -------------------------------------------------------------------------------- 1 | # IRremote ESP8266 Library 2 | 3 | This library enables you to **send and receive** infra-red signals on an ESP8266 using Arduino framework (https://github.com/esp8266/Arduino) 4 | 5 | This library is based on Ken Shirriff's work (https://github.com/shirriff/Arduino-IRremote/) 6 | 7 | [Mark Szabo](https://github.com/markszabo/IRremoteESP8266) has updated the IRsend class to work on ESP8266 and [Sebastien Warin](https://github.com/sebastienwarin/IRremoteESP8266) the receiving & decoding part (IRrecv class). 8 | 9 | Seb's notes : I also changed the pulse parameters for Samsung, update the Panasonic and Samsung decoders and remove the SANYO decoders. The IR decoder was successfully tested with Panasonic and Samsung remote controls. 10 | 11 | ## Installation 12 | 1. Click "Download ZIP" 13 | 2. Extract the downloaded zip file 14 | 3. Rename the extracted folder to "IRremoteESP8266" 15 | 4. Move this folder to your libraries directory (under windows: C:\Users\YOURNAME\Documents\Arduino\libraries\) 16 | 5. Restart your Arduino ide 17 | 6. Check out the examples 18 | 19 | ## Contributing 20 | If you want to contribute to this project: 21 | - Report bugs and errors 22 | - Ask for enhancements 23 | - Create issues and pull requests 24 | - Tell other people about this library 25 | 26 | ## Contributors 27 | Check [here](Contributors.md) 28 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/lib/IRremoteESP8266/examples/IRServer/IRServer.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremoteESP8266: IRServer - demonstrates sending IR codes controlled from a webserver 3 | * An IR LED must be connected to ESP8266 pin 0. 4 | * Version 0.1 June, 2015 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | const char* ssid = "....."; 14 | const char* password = "....."; 15 | MDNSResponder mdns; 16 | 17 | ESP8266WebServer server(80); 18 | 19 | IRsend irsend(0); 20 | 21 | void handleRoot() { 22 | server.send(200, "text/html", " ESP8266 Demo

Hello from ESP8266, you can send NEC encoded IR signals from here!

Send 0xFFE01F

Send 0xFAB123

Send 0xFFE896

"); 23 | } 24 | 25 | void handleIr(){ 26 | for (uint8_t i=0; i 9 | 10 | int RECV_PIN = 2; //an IR detector/demodulatord is connected to GPIO pin 2 11 | 12 | IRrecv irrecv(RECV_PIN); 13 | 14 | decode_results results; 15 | 16 | void setup() 17 | { 18 | Serial.begin(9600); 19 | irrecv.enableIRIn(); // Start the receiver 20 | } 21 | 22 | void loop() { 23 | if (irrecv.decode(&results)) { 24 | Serial.println(results.value, HEX); 25 | irrecv.resume(); // Receive the next value 26 | } 27 | delay(100); 28 | } 29 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/lib/IRremoteESP8266/examples/IRrecvDump/IRrecvDump.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremoteESP8266: IRrecvDump - dump details of IR codes with IRrecv 3 | * An IR detector/demodulator must be connected to the input RECV_PIN. 4 | * Version 0.1 Sept, 2015 5 | * Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009, Copyright 2009 Ken Shirriff, http://arcfn.com 6 | * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) 7 | * LG added by Darryl Smith (based on the JVC protocol) 8 | */ 9 | 10 | #include 11 | 12 | int RECV_PIN = 2; //an IR detector/demodulatord is connected to GPIO pin 2 13 | 14 | IRrecv irrecv(RECV_PIN); 15 | 16 | decode_results results; 17 | 18 | void setup() 19 | { 20 | Serial.begin(9600); 21 | irrecv.enableIRIn(); // Start the receiver 22 | } 23 | 24 | 25 | void dump(decode_results *results) { 26 | // Dumps out the decode_results structure. 27 | // Call this after IRrecv::decode() 28 | int count = results->rawlen; 29 | if (results->decode_type == UNKNOWN) { 30 | Serial.print("Unknown encoding: "); 31 | } 32 | else if (results->decode_type == NEC) { 33 | Serial.print("Decoded NEC: "); 34 | 35 | } 36 | else if (results->decode_type == SONY) { 37 | Serial.print("Decoded SONY: "); 38 | } 39 | else if (results->decode_type == RC5) { 40 | Serial.print("Decoded RC5: "); 41 | } 42 | else if (results->decode_type == RC6) { 43 | Serial.print("Decoded RC6: "); 44 | } 45 | else if (results->decode_type == PANASONIC) { 46 | Serial.print("Decoded PANASONIC - Address: "); 47 | Serial.print(results->panasonicAddress, HEX); 48 | Serial.print(" Value: "); 49 | } 50 | else if (results->decode_type == LG) { 51 | Serial.print("Decoded LG: "); 52 | } 53 | else if (results->decode_type == JVC) { 54 | Serial.print("Decoded JVC: "); 55 | } 56 | else if (results->decode_type == AIWA_RC_T501) { 57 | Serial.print("Decoded AIWA RC T501: "); 58 | } 59 | else if (results->decode_type == WHYNTER) { 60 | Serial.print("Decoded Whynter: "); 61 | } 62 | Serial.print(results->value, HEX); 63 | Serial.print(" ("); 64 | Serial.print(results->bits, DEC); 65 | Serial.println(" bits)"); 66 | Serial.print("Raw ("); 67 | Serial.print(count, DEC); 68 | Serial.print("): "); 69 | 70 | for (int i = 1; i < count; i++) { 71 | if (i & 1) { 72 | Serial.print(results->rawbuf[i]*USECPERTICK, DEC); 73 | } 74 | else { 75 | Serial.write('-'); 76 | Serial.print((unsigned long) results->rawbuf[i]*USECPERTICK, DEC); 77 | } 78 | Serial.print(" "); 79 | } 80 | Serial.println(); 81 | } 82 | 83 | void loop() { 84 | if (irrecv.decode(&results)) { 85 | Serial.println(results.value, HEX); 86 | dump(&results); 87 | irrecv.resume(); // Receive the next value 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/lib/IRremoteESP8266/examples/IRrecvDumpV2/IRrecvDumpV2.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremoteESP8266: IRrecvDumpV2 - dump details of IR codes with IRrecv 3 | * An IR detector/demodulator must be connected to the input RECV_PIN. 4 | * Version 0.1 Sept, 2015 5 | * Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009, Copyright 2009 Ken Shirriff, http://arcfn.com 6 | */ 7 | 8 | #include 9 | 10 | int RECV_PIN = 2; //an IR detector/demodulator is connected to GPIO pin 2 11 | 12 | IRrecv irrecv(RECV_PIN); 13 | 14 | void setup ( ) 15 | { 16 | Serial.begin(9600); // Status message will be sent to PC at 9600 baud 17 | irrecv.enableIRIn(); // Start the receiver 18 | } 19 | 20 | //+============================================================================= 21 | // Display IR code 22 | // 23 | void ircode (decode_results *results) 24 | { 25 | // Panasonic has an Address 26 | if (results->decode_type == PANASONIC) { 27 | Serial.print(results->panasonicAddress, HEX); 28 | Serial.print(":"); 29 | } 30 | 31 | // Print Code 32 | Serial.print(results->value, HEX); 33 | } 34 | 35 | //+============================================================================= 36 | // Display encoding type 37 | // 38 | void encoding (decode_results *results) 39 | { 40 | switch (results->decode_type) { 41 | default: 42 | case UNKNOWN: Serial.print("UNKNOWN"); break ; 43 | case NEC: Serial.print("NEC"); break ; 44 | case SONY: Serial.print("SONY"); break ; 45 | case RC5: Serial.print("RC5"); break ; 46 | case RC6: Serial.print("RC6"); break ; 47 | case DISH: Serial.print("DISH"); break ; 48 | case SHARP: Serial.print("SHARP"); break ; 49 | case JVC: Serial.print("JVC"); break ; 50 | case SANYO: Serial.print("SANYO"); break ; 51 | case MITSUBISHI: Serial.print("MITSUBISHI"); break ; 52 | case SAMSUNG: Serial.print("SAMSUNG"); break ; 53 | case LG: Serial.print("LG"); break ; 54 | case WHYNTER: Serial.print("WHYNTER"); break ; 55 | case AIWA_RC_T501: Serial.print("AIWA_RC_T501"); break ; 56 | case PANASONIC: Serial.print("PANASONIC"); break ; 57 | } 58 | } 59 | 60 | //+============================================================================= 61 | // Dump out the decode_results structure. 62 | // 63 | void dumpInfo (decode_results *results) 64 | { 65 | // Show Encoding standard 66 | Serial.print("Encoding : "); 67 | encoding(results); 68 | Serial.println(""); 69 | 70 | // Show Code & length 71 | Serial.print("Code : "); 72 | ircode(results); 73 | Serial.print(" ("); 74 | Serial.print(results->bits, DEC); 75 | Serial.println(" bits)"); 76 | } 77 | 78 | //+============================================================================= 79 | // Dump out the decode_results structure. 80 | // 81 | void dumpRaw (decode_results *results) 82 | { 83 | // Print Raw data 84 | Serial.print("Timing["); 85 | Serial.print(results->rawlen-1, DEC); 86 | Serial.println("]: "); 87 | 88 | for (int i = 1; i < results->rawlen; i++) { 89 | unsigned long x = results->rawbuf[i] * USECPERTICK; 90 | if (!(i & 1)) { // even 91 | Serial.print("-"); 92 | if (x < 1000) Serial.print(" ") ; 93 | if (x < 100) Serial.print(" ") ; 94 | Serial.print(x, DEC); 95 | } else { // odd 96 | Serial.print(" "); 97 | Serial.print("+"); 98 | if (x < 1000) Serial.print(" ") ; 99 | if (x < 100) Serial.print(" ") ; 100 | Serial.print(x, DEC); 101 | if (i < results->rawlen-1) Serial.print(", "); //',' not needed for last one 102 | } 103 | if (!(i % 8)) Serial.println(""); 104 | } 105 | Serial.println(""); // Newline 106 | } 107 | 108 | //+============================================================================= 109 | // Dump out the decode_results structure. 110 | // 111 | void dumpCode (decode_results *results) 112 | { 113 | // Start declaration 114 | Serial.print("unsigned int "); // variable type 115 | Serial.print("rawData["); // array name 116 | Serial.print(results->rawlen - 1, DEC); // array size 117 | Serial.print("] = {"); // Start declaration 118 | 119 | // Dump data 120 | for (int i = 1; i < results->rawlen; i++) { 121 | Serial.print(results->rawbuf[i] * USECPERTICK, DEC); 122 | if ( i < results->rawlen-1 ) Serial.print(","); // ',' not needed on last one 123 | if (!(i & 1)) Serial.print(" "); 124 | } 125 | 126 | // End declaration 127 | Serial.print("};"); // 128 | 129 | // Comment 130 | Serial.print(" // "); 131 | encoding(results); 132 | Serial.print(" "); 133 | ircode(results); 134 | 135 | // Newline 136 | Serial.println(""); 137 | 138 | // Now dump "known" codes 139 | if (results->decode_type != UNKNOWN) { 140 | 141 | // Some protocols have an address 142 | if (results->decode_type == PANASONIC) { 143 | Serial.print("unsigned int addr = 0x"); 144 | Serial.print(results->panasonicAddress, HEX); 145 | Serial.println(";"); 146 | } 147 | 148 | // All protocols have data 149 | Serial.print("unsigned int data = 0x"); 150 | Serial.print(results->value, HEX); 151 | Serial.println(";"); 152 | } 153 | } 154 | 155 | //+============================================================================= 156 | // The repeating section of the code 157 | // 158 | void loop ( ) 159 | { 160 | decode_results results; // Somewhere to store the results 161 | 162 | if (irrecv.decode(&results)) { // Grab an IR code 163 | dumpInfo(&results); // Output the results 164 | dumpRaw(&results); // Output the results in RAW format 165 | dumpCode(&results); // Output the results as source code 166 | Serial.println(""); // Blank line between entries 167 | irrecv.resume(); // Prepare for the next value 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/lib/IRremoteESP8266/examples/IRsendDemo/IRsendDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremoteESP8266: IRsendDemo - demonstrates sending IR codes with IRsend 3 | * An IR LED must be connected to ESP8266 pin 0. 4 | * Version 0.1 June, 2015 5 | * Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009, Copyright 2009 Ken Shirriff, http://arcfn.com 6 | */ 7 | 8 | #include 9 | 10 | IRsend irsend(0); //an IR led is connected to GPIO pin 0 11 | 12 | void setup() 13 | { 14 | irsend.begin(); 15 | Serial.begin(9600); 16 | } 17 | 18 | void loop() { 19 | Serial.println("NEC"); 20 | irsend.sendNEC(0x00FFE01F, 36); 21 | delay(2000); 22 | Serial.println("Sony"); 23 | irsend.sendSony(0xa90, 12); 24 | delay(2000); 25 | } 26 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/lib/IRremoteESP8266/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremoteESP8266: IRsendDemo - demonstrates sending IR codes with IRsend 3 | * An IR LED must be connected to ESP8266 pin 0. 4 | * Version 0.1 June, 2015 5 | * Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009, Copyright 2009 Ken Shirriff, http://arcfn.com 6 | * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) 7 | */ 8 | #include 9 | 10 | #define PanasonicAddress 0x4004 // Panasonic address (Pre data) 11 | #define PanasonicPower 0x100BCBD // Panasonic Power button 12 | 13 | #define JVCPower 0xC5E8 14 | 15 | IRsend irsend(0); //an IR led is connected to GPIO pin 0 16 | 17 | void setup() 18 | { 19 | irsend.begin(); 20 | } 21 | 22 | void loop() { 23 | irsend.sendPanasonic(PanasonicAddress,PanasonicPower); // This should turn your TV on and off 24 | 25 | irsend.sendJVC(JVCPower, 16,0); // hex value, 16 bits, no repeat 26 | delayMicroseconds(50); // see http://www.sbprojects.com/knowledge/ir/jvc.php for information 27 | irsend.sendJVC(JVCPower, 16,1); // hex value, 16 bits, repeat 28 | delayMicroseconds(50); 29 | } 30 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/lib/IRremoteESP8266/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For IRremote 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | decode_results KEYWORD1 10 | IRrecv KEYWORD1 11 | IRsend KEYWORD1 12 | 13 | ####################################### 14 | # Methods and Functions (KEYWORD2) 15 | ####################################### 16 | 17 | decode KEYWORD2 18 | enableIRIn KEYWORD2 19 | disableIRIn KEYWORD2 20 | resume KEYWORD2 21 | begin KEYWORD2 22 | enableIROut KEYWORD2 23 | sendNEC KEYWORD2 24 | sendSony KEYWORD2 25 | sendSanyo KEYWORD2 26 | sendMitsubishi KEYWORD2 27 | sendRaw KEYWORD2 28 | sendRC5 KEYWORD2 29 | sendRC6 KEYWORD2 30 | sendDISH KEYWORD2 31 | sendSharp KEYWORD2 32 | sendSharpRaw KEYWORD2 33 | sendPanasonic KEYWORD2 34 | sendJVC KEYWORD2 35 | sendWhynter KEYWORD2 36 | sendSAMSUNG KEYWORD2 37 | 38 | ####################################### 39 | # Constants (LITERAL1) 40 | ####################################### 41 | 42 | NEC LITERAL1 43 | SONY LITERAL1 44 | SANYO LITERAL1 45 | MITSUBISHI LITERAL1 46 | RC5 LITERAL1 47 | RC6 LITERAL1 48 | DISH LITERAL1 49 | SHARP LITERAL1 50 | PANASONIC LITERAL1 51 | JVC LITERAL1 52 | LG LITERAL1 53 | SAMSUNG LITERAL1 54 | WHYNTER LITERAL1 55 | AIWA_RC_T501 LITERAL1 56 | UNKNOWN LITERAL1 57 | REPEAT LITERAL1 -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/lib/IRremoteESP8266/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "IRremoteESP8266", 3 | "keywords": "infrared, ir, remote", 4 | "description": "Send and receive infrared signals with multiple protocols", 5 | "repository": 6 | { 7 | "type": "git", 8 | "url": "https://github.com/sebastienwarin/IRremoteESP8266.git" 9 | }, 10 | "frameworks": "arduino", 11 | "platforms": "esp8266" 12 | } 13 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/lib/IRremoteESP8266/library.properties: -------------------------------------------------------------------------------- 1 | name=IRremoteESP8266 2 | version=1.0.0 3 | author=Sebastien Warin, Mark Szabo, Ken Shirriff 4 | maintainer=Sebastien Warin 5 | sentence=Send and receive infrared signals with multiple protocols. 6 | paragraph=This library enables you to send and receive infra-red signals on an ESP8266. 7 | category=Device Control 8 | url=https://github.com/sebastienwarin/IRremoteESP8266 9 | architectures=esp8266 10 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/platformio.ini: -------------------------------------------------------------------------------- 1 | # 2 | # Example PlatformIO configuration file for SSL and non-SSL builds. 3 | # 4 | # Before you will be able to build the SSL version of this project, you will 5 | # need to explicitly install the espressif8266_stage platform. 6 | # 7 | # To perform this installation, refer to step 1 of: 8 | # http://docs.platformio.org/en/latest/platforms/espressif8266.html#using-arduino-framework-with-staging-version 9 | 10 | [platformio] 11 | env_default = nossl 12 | 13 | [common] 14 | framework = arduino 15 | lib_deps = ESP8266MQTTMesh 16 | 17 | [env:nossl] 18 | platform = espressif8266 19 | framework = arduino 20 | board = esp01_1m 21 | lib_deps = ${common.lib_deps} 22 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/src/ESP8266MeshIRRemote.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 PhracturedBlue 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Based on IRremoteESP8266: IRServer - demonstrates sending IR codes controlled from a webserver 18 | * 19 | * esp8266IR Remote allows Pronto IR codes to be sent via an IR LED connected on GPIO2 via http 20 | * It is recommended to drive an n-fet transistor connected to a resistor and diode, since the 21 | * esp8266 can only supply 12mA on its GPIO pin. 22 | * 23 | * Known commands: 24 | * NOTE: The maximum length of topic + payload is ~1156 bytes 25 | * /send : code= : send specified code one time 26 | * /send : repeat=5,code= : send specified code 5 times 27 | * /send : repeat=5,code=,repeat=3,pronto= : send code1 5 times followed by sending code2 3 times 28 | * /send : repeat=5,file= : send pronto code previously saved in 'filename' 5 times 29 | * /list : "" : returns a list of all saved files 30 | * /debug: <1|0> : enable/disable debugging messages over MQTT 31 | * /save/ : code= : save specified pronto code to 'filename' on esp8266 device 32 | * /read/ : "" : return contents of 'flename' via MQTT 33 | * 34 | * will generally be something like: 'esp8266-in/mesh_esp8266-7' 35 | * Version 0.2 2017-04-16 36 | */ 37 | 38 | /* See credentials.h.examle for contents of credentials.h */ 39 | #include "credentials.h" 40 | #include 41 | #include 42 | 43 | #include 44 | #include 45 | #include "QueueArray.h" 46 | 47 | #define FIRMWARE_ID 0x2222 48 | #define FIRMWARE_VER "0.2" 49 | 50 | const wifi_conn networks[] = NETWORK_LIST; 51 | const char* mqtt_server = MQTT_SERVER; 52 | const char* mesh_password = MESH_PASSWORD; 53 | 54 | ESP8266MQTTMesh mesh = ESP8266MQTTMesh::Builder(networks, mqtt_server) 55 | .setVersion(FIRMWARE_VER, FIRMWARE_ID) 56 | .setMeshPassword(mesh_password) 57 | .build(); 58 | 59 | #define ESP8266_LED 2 60 | 61 | bool debug = false; 62 | 63 | class Cmd { 64 | public: 65 | Cmd(String _c, int _r, String _p, String _d = "") { 66 | code = _c; 67 | repeat = _r; 68 | protocol = _p; 69 | description = _d; 70 | } 71 | String code; 72 | String protocol; 73 | String description; 74 | int repeat; 75 | }; 76 | QueueArray cmdQueue(10); 77 | 78 | IRsend irsend(ESP8266_LED); 79 | 80 | void handleList() { 81 | String message = "{ \"Commands\": {"; 82 | Dir dir = SPIFFS.openDir("/ir/"); 83 | bool first = true; 84 | while(dir.next()) { 85 | if (! first) { 86 | message += ","; 87 | } 88 | File f = dir.openFile("r"); 89 | int size = f.size(); 90 | f.close(); 91 | message += " \"" + dir.fileName().substring(4) + "\": " + String(size); 92 | first = false; 93 | } 94 | FSInfo fs_info; 95 | SPIFFS.info(fs_info); 96 | message += " }, \"Free\": " + String(fs_info.totalBytes - fs_info.usedBytes) + "}"; 97 | mesh.publish("list", message.c_str()); 98 | } 99 | 100 | Cmd *parse_code(const char *msg, bool queue = false) { 101 | String code = ""; 102 | String protocol = "pronto"; 103 | int repeat = 0; 104 | bool debug = false; 105 | bool seen_repeat = false; 106 | while (msg) { 107 | char kv[1024]; 108 | char key[16]; 109 | const char *value; 110 | ESP8266MQTTMesh::keyValue(msg, ',', kv, sizeof(kv), &msg); 111 | if (! ESP8266MQTTMesh::keyValue(kv, '=', key, sizeof(key), &value)) { 112 | continue; 113 | }; 114 | if (0 == strcmp(key, "repeat")) { 115 | repeat = atoi(value); 116 | seen_repeat = true; 117 | } 118 | else if (0 == strcmp(key, "protocol")) { 119 | protocol = value; 120 | } 121 | else if(0 == strcmp(key, "code")) { 122 | code = value; 123 | if (queue) { 124 | cmdQueue.push(new Cmd(code, repeat, protocol, "Code len: " + String(code.length()))); 125 | } 126 | } 127 | else if(0 == strcmp(key, "file")) { 128 | File f = SPIFFS.open("/ir/" + String(value), "r"); 129 | if (! f) { 130 | Serial.println("Failed to read file: " + String(value)); 131 | continue; 132 | } 133 | protocol = f.readStringUntil('\n'); 134 | code = f.readStringUntil('\n'); 135 | String repeat_str = f.readStringUntil('\n'); 136 | if (repeat_str != "" && !seen_repeat) { 137 | repeat = repeat_str.toInt(); 138 | } 139 | if (queue) { 140 | cmdQueue.push(new Cmd(code, repeat, protocol, "File: " + String(value))); 141 | } 142 | f.close(); 143 | } 144 | } 145 | if (queue) { 146 | return NULL; 147 | } 148 | Cmd *cmd = new Cmd(code, repeat, protocol); 149 | return cmd; 150 | } 151 | 152 | void callback(const char *topic, const char *msg) 153 | { 154 | char *endStr; 155 | if (0 == strcmp(topic, "list")) { 156 | handleList(); 157 | } 158 | if (0 == strcmp(topic, "debug")) { 159 | debug = atoi(msg); 160 | } 161 | else if (0 == strcmp(topic, "send")) { 162 | parse_code(msg, true); 163 | } 164 | else if (strstr(topic, "read/") == topic) { 165 | const char *filename = topic + 5; 166 | File f = SPIFFS.open("/ir/" + String(filename), "r"); 167 | if (! f) { 168 | Serial.println("Failed to read file: " + String(filename)); 169 | mesh.publish(topic, "{ \"Failed\": 1 }"); 170 | return; 171 | } 172 | String json = "{"; 173 | json += " \"protocol\": \"" + f.readStringUntil('\n') + "\""; 174 | json += " \"code\": \"" + f.readStringUntil('\n') + "\""; 175 | json += " \"repeat\": \"" + f.readStringUntil('\n') + "\""; 176 | json += " }"; 177 | mesh.publish(topic, json.c_str()); 178 | } 179 | else if (strstr(topic, "save/") == topic) { 180 | const char *filename = topic + 5; 181 | Cmd *cmd = parse_code(msg); 182 | File f = SPIFFS.open("/ir/" + String(filename), "w"); 183 | if (! f) { 184 | Serial.println("Failed to create file: " + String(filename)); 185 | mesh.publish(topic, "{ \"Failed\": 1 }"); 186 | } else { 187 | f.print(cmd->protocol + "\n"); 188 | f.print(cmd->code + "\n"); 189 | f.print(String(cmd->repeat) + "\n"); 190 | f.close(); 191 | } 192 | delete cmd; 193 | } 194 | } 195 | void setup(void){ 196 | irsend.begin(); 197 | 198 | Serial.begin(115200); 199 | mesh.setCallback(callback); 200 | mesh.begin(); 201 | Serial.println(""); 202 | if (1) { 203 | FSInfo fs_info; 204 | SPIFFS.info(fs_info); 205 | Serial.print("FS Used: "); 206 | Serial.print(fs_info.usedBytes); 207 | Serial.print(" Free: "); 208 | Serial.print(fs_info.totalBytes - fs_info.usedBytes); 209 | Serial.print(" Blocksize: "); 210 | Serial.println(fs_info.blockSize); 211 | Dir dir = SPIFFS.openDir("/ir/"); 212 | while(dir.next()) { 213 | Serial.println("File: " + dir.fileName()); 214 | } 215 | } 216 | } 217 | 218 | void loop(void){ 219 | if (! cmdQueue.isEmpty()) { 220 | Cmd *nextCmd = cmdQueue.peek(); 221 | Serial.println("Sendng code: Repeat=" + String(nextCmd->repeat) + " queue size= " + cmdQueue.count()); 222 | if (debug) { 223 | mesh.publish("tx", String("Queue Len: " + String(cmdQueue.count()) + " Repeat: " + String(nextCmd->repeat) + " Desc: " + nextCmd->description).c_str()); 224 | } 225 | while (1) { 226 | irsend.sendPronto(nextCmd->code.c_str(), nextCmd->repeat ? true : false, true); 227 | if (nextCmd->repeat >= -1) { 228 | break; 229 | } 230 | nextCmd->repeat++; 231 | } 232 | //irsend.sendPronto(nextCmd->code.c_str(), nextCmd->repeat ? true : false, true); 233 | if (nextCmd->repeat <= 1) { 234 | nextCmd = cmdQueue.pop(); 235 | delete nextCmd; 236 | } else { 237 | nextCmd->repeat--; 238 | } 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /examples/ESP8266MeshIRRemote/src/QueueArray.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QueueArray.h 3 | * 4 | * Library implementing a generic, dynamic queue (array version). 5 | * 6 | * --- 7 | * 8 | * Copyright (C) 2010 Efstathios Chatzikyriakidis (contact@efxa.org) 9 | * 10 | * This program is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation, either version 3 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program. If not, see . 22 | * 23 | * --- 24 | * 25 | * 2013-11-07 Marcus Nowotny 26 | * - pushing to a full array does not crash but returns false 27 | * 28 | * 2013-11-05 Marcus Nowotny 29 | * - rewritten to use a default size 30 | * - texts are now in flash 31 | * 32 | * Version 1.0 33 | * 34 | * 2010-09-29 Efstathios Chatzikyriakidis 35 | * 36 | * - added resize(): for growing, shrinking the array size. 37 | * 38 | * 2010-09-25 Efstathios Chatzikyriakidis 39 | * 40 | * - added exit(), blink(): error reporting and handling methods. 41 | * 42 | * 2010-09-24 Alexander Brevig 43 | * 44 | * - added setPrinter(): indirectly reference a Serial object. 45 | * 46 | * 2010-09-20 Efstathios Chatzikyriakidis 47 | * 48 | * - initial release of the library. 49 | * 50 | * --- 51 | * 52 | * For the latest version see: http://www.arduino.cc/ 53 | */ 54 | 55 | // header defining the interface of the source. 56 | #ifndef _QUEUEARRAY_H 57 | #define _QUEUEARRAY_H 58 | 59 | // include Arduino basic header. 60 | #include 61 | 62 | // the definition of the queue class. 63 | template 64 | class QueueArray { 65 | public: 66 | // init the queue (constructor). 67 | QueueArray (const uint16_t initialSize); 68 | 69 | // clear the queue (destructor). 70 | ~QueueArray (); 71 | 72 | // push an item to the queue. 73 | bool push (const T i); 74 | 75 | // pop an item from the queue. 76 | T pop (); 77 | 78 | // get an item from the queue. 79 | T peek () const; 80 | 81 | // check if the queue is empty. 82 | bool isEmpty () const; 83 | 84 | // get the number of items in the queue. 85 | uint16_t count () const; 86 | 87 | // check if the queue is full. 88 | bool isFull () const; 89 | 90 | // set the printer of the queue. 91 | void setStream (Stream & s); 92 | 93 | private: 94 | 95 | // exit report method in case of error. 96 | void exit(const __FlashStringHelper*) const; 97 | 98 | // led blinking method in case of error. 99 | void blink () const; 100 | 101 | Stream * stream; // the printer of the queue. 102 | T * contents; // the array of the queue. 103 | 104 | uint16_t size; // the size of the queue. 105 | uint16_t items; // the number of items of the queue. 106 | 107 | uint16_t head; // the head of the queue. 108 | uint16_t tail; // the tail of the queue. 109 | }; 110 | 111 | // init the queue (constructor). 112 | template 113 | QueueArray::QueueArray (const uint16_t initialSize) { 114 | size = 0; // set the size of queue to zero. 115 | items = 0; // set the number of items of queue to zero. 116 | 117 | head = 0; // set the head of the queue to zero. 118 | tail = 0; // set the tail of the queue to zero. 119 | 120 | stream = NULL; // set the printer of queue to point nowhere. 121 | 122 | // allocate enough memory for the array. 123 | contents = (T *) malloc (sizeof (T) * initialSize); 124 | 125 | // if there is a memory allocation error. 126 | if (contents == NULL) 127 | exit (F("QUEUE: insufficient memory to initialize queue.")); 128 | 129 | // set the initial size of the queue. 130 | size = initialSize; 131 | } 132 | 133 | // clear the queue (destructor). 134 | template 135 | QueueArray::~QueueArray () { 136 | free (contents); // deallocate the array of the queue. 137 | 138 | contents = NULL; // set queue's array pointer to nowhere. 139 | stream = NULL; // set the printer of queue to point nowhere. 140 | 141 | size = 0; // set the size of queue to zero. 142 | items = 0; // set the number of items of queue to zero. 143 | 144 | head = 0; // set the head of the queue to zero. 145 | tail = 0; // set the tail of the queue to zero. 146 | } 147 | 148 | // push an item to the queue. 149 | template 150 | bool QueueArray::push (const T i) { 151 | // check if the queue is full. 152 | if (isFull ()) 153 | // we cannot add anythif - just return false 154 | return false; 155 | 156 | // store the item to the array. 157 | contents[tail++] = i; 158 | 159 | // wrap-around index. 160 | if (tail == size) tail = 0; 161 | 162 | // increase the items. 163 | items++; 164 | 165 | //ok everything was fin 166 | return true; 167 | } 168 | 169 | // pop an item from the queue. 170 | template 171 | T QueueArray::pop () { 172 | // check if the queue is empty. 173 | if (isEmpty ()) 174 | exit (F("QUEUE: can't pop item from queue: queue is empty.")); 175 | 176 | // fetch the item from the array. 177 | T item = contents[head++]; 178 | 179 | // decrease the items. 180 | items--; 181 | 182 | // wrap-around index. 183 | if (head == size) head = 0; 184 | 185 | // return the item from the array. 186 | return item; 187 | } 188 | 189 | // get an item from the queue. 190 | template 191 | T QueueArray::peek () const { 192 | // check if the queue is empty. 193 | if (isEmpty ()) 194 | exit (F("QUEUE: can't peek item from queue: queue is empty.")); 195 | 196 | // get the item from the array. 197 | return contents[head]; 198 | } 199 | 200 | // check if the queue is empty. 201 | template 202 | bool QueueArray::isEmpty () const { 203 | return items == 0; 204 | } 205 | 206 | // check if the queue is full. 207 | template 208 | bool QueueArray::isFull () const { 209 | return items == size; 210 | } 211 | 212 | // get the number of items in the queue. 213 | template 214 | uint16_t QueueArray::count () const { 215 | return items; 216 | } 217 | 218 | // set the printer of the queue. 219 | template 220 | void QueueArray::setStream (Stream & s) { 221 | stream = &s; 222 | } 223 | 224 | // exit report method in case of error. 225 | template 226 | void QueueArray::exit (const __FlashStringHelper * m) const { 227 | // print the message if there is a printer. 228 | if (stream) 229 | stream->println (m); 230 | 231 | // loop blinking until hardware reset. 232 | blink (); 233 | } 234 | 235 | // led blinking method in case of error. 236 | template 237 | void QueueArray::blink () const { 238 | while(1); 239 | // solution selected due to lack of exit() and assert(). 240 | } 241 | 242 | #endif // _QUEUEARRAY_H 243 | -------------------------------------------------------------------------------- /examples/ESP8266MeshSensor/Makefile: -------------------------------------------------------------------------------- 1 | #==================================================================================== 2 | # makeESPArduino 3 | # 4 | # A makefile for ESP8286 and ESP32 Arduino projects. 5 | # Edit the contents of this file to suit your project 6 | # or just include it and override the applicable macros. 7 | # 8 | # License: GPL 2.1 9 | # General and full license information is available at: 10 | # https://github.com/plerup/makeEspArduino 11 | # 12 | # Copyright (c) 2016-2017 Peter Lerup. All rights reserved. 13 | # 14 | #==================================================================================== 15 | 16 | #==================================================================================== 17 | # Project specfic values 18 | #==================================================================================== 19 | 20 | # Include possible project makefile. This can be used to override the defaults below 21 | -include $(firstword $(PROJ_CONF) $(dir $(SKETCH))config.mk) 22 | 23 | #=== Default values not available in the Arduino configuration files 24 | 25 | CHIP ?= esp8266 26 | 27 | # Set chip specific default board unless specified 28 | BOARD ?= $(if $(filter $(CHIP), esp32),esp32,generic) 29 | 30 | # Serial flashing parameters 31 | UPLOAD_PORT ?= $(shell ls -1tr /dev/ttyUSB* | tail -1) 32 | UPLOAD_VERB ?= -v 33 | 34 | # OTA parameters 35 | ESP_ADDR ?= ESP_123456 36 | ESP_PORT ?= 8266 37 | ESP_PWD ?= 123 38 | 39 | # HTTP update parameters 40 | HTTP_ADDR ?= ESP_123456 41 | HTTP_URI ?= /update 42 | HTTP_PWD ?= user 43 | HTTP_USR ?= password 44 | 45 | # Output directory 46 | BUILD_DIR ?= /tmp/mkESP/$(MAIN_NAME)_$(BOARD) 47 | 48 | # File system source directory 49 | FS_DIR ?= $(dir $(SKETCH))data 50 | 51 | # Bootloader 52 | BOOT_LOADER ?= $(ESP_ROOT)/bootloaders/eboot/eboot.elf 53 | 54 | #==================================================================================== 55 | # Standard build logic and values 56 | #==================================================================================== 57 | 58 | START_TIME := $(shell perl -e "print time();") 59 | 60 | # Utility functions 61 | git_description = $(shell git -C $(1) describe --tags --always --dirty 2>/dev/null || echo Unknown) 62 | time_string = $(shell date +$(1)) 63 | 64 | # ESP Arduino directories 65 | ifndef ESP_ROOT 66 | # Location not defined, find and use possible version in the Arduino IDE installation 67 | OS ?= $(shell uname -s) 68 | ifeq ($(OS), Windows_NT) 69 | ARDUINO_DIR = $(shell cygpath -m $(LOCALAPPDATA)/Arduino15/packages/$(CHIP)) 70 | else ifeq ($(OS), Darwin) 71 | ARDUINO_DIR = $(HOME)/Library/Arduino15/packages/$(CHIP) 72 | else 73 | ARDUINO_DIR = $(HOME)/.arduino15/packages/$(CHIP) 74 | endif 75 | ESP_ROOT := $(lastword $(wildcard $(ARDUINO_DIR)/hardware/$(CHIP)/*)) 76 | ifeq ($(ESP_ROOT),) 77 | $(error No installed version of $(CHIP) Arduino found) 78 | endif 79 | ESP_ARDUINO_VERSION := $(notdir $(ESP_ROOT)) 80 | # Find used version of compiler and tools 81 | COMP_PATH := $(lastword $(wildcard $(ARDUINO_DIR)/tools/xtensa-lx106-elf-gcc/*)) 82 | ESPTOOL_PATH := $(lastword $(wildcard $(ARDUINO_DIR)/tools/esptool/*)) 83 | MKSPIFFS_PATH := $(lastword $(wildcard $(ARDUINO_DIR)/tools/mkspiffs/*)) 84 | else 85 | # Location defined, assume it is a git clone 86 | ESP_ARDUINO_VERSION = $(call git_description,$(ESP_ROOT)) 87 | endif 88 | ESP_LIBS = $(ESP_ROOT)/libraries 89 | SDK_ROOT = $(ESP_ROOT)/tools/sdk 90 | TOOLS_ROOT = $(ESP_ROOT)/tools 91 | 92 | ifeq ($(wildcard $(ESP_ROOT)/cores/$(CHIP)),) 93 | $(error $(ESP_ROOT) is not a vaild directory for $(CHIP)) 94 | endif 95 | 96 | ESPTOOL_PY = esptool.py --baud=$(UPLOAD_SPEED) --port $(UPLOAD_PORT) 97 | 98 | # Search for sketch if not defined 99 | SKETCH := $(realpath $(firstword \ 100 | $(SKETCH) \ 101 | $(wildcard *.ino) \ 102 | $(if $(filter $(CHIP), esp32),$(ESP_LIBS)/WiFi/examples/WiFiScan/WiFiScan.ino,$(ESP_LIBS)/ESP8266WebServer/examples/HelloServer/HelloServer.ino) \ 103 | ) \ 104 | ) 105 | ifeq ($(wildcard $(SKETCH)),) 106 | $(error Sketch $(SKETCH) not found) 107 | endif 108 | 109 | # Main output definitions 110 | MAIN_NAME := $(basename $(notdir $(SKETCH))) 111 | MAIN_EXE = $(BUILD_DIR)/$(MAIN_NAME).bin 112 | FS_IMAGE = $(BUILD_DIR)/FS.spiffs 113 | 114 | ifeq ($(OS), Windows_NT) 115 | # Adjust critical paths 116 | BUILD_DIR := $(shell cygpath -m $(BUILD_DIR)) 117 | SKETCH := $(shell cygpath -m $(SKETCH)) 118 | endif 119 | 120 | # Build file extensions 121 | OBJ_EXT = .o 122 | DEP_EXT = .d 123 | 124 | # Special tool definitions 125 | OTA_TOOL ?= $(TOOLS_ROOT)/espota.py 126 | HTTP_TOOL ?= curl 127 | 128 | # Core source files 129 | CORE_DIR = $(ESP_ROOT)/cores/$(CHIP) 130 | CORE_SRC := $(shell find $(CORE_DIR) -name "*.S" -o -name "*.c" -o -name "*.cpp") 131 | CORE_OBJ := $(patsubst %,$(BUILD_DIR)/%$(OBJ_EXT),$(notdir $(CORE_SRC))) 132 | CORE_LIB = $(BUILD_DIR)/arduino.ar 133 | 134 | # User defined compilation units and directories 135 | ifeq ($(LIBS),) 136 | # Automatically find directories with header files used by the sketch 137 | FINDCMD := perl -e 'use File::Find;@d = split(" ", shift);while (<>) {$$f{"$$1"} = 1 if /^\s*\#include\s+[<"]([^>"]+)/;}find({follow => 1, wanted => sub {return if($$File::Find::dir =~ /examples|tests/);print $$File::Find::dir," " if $$f{$$_}}}, @d);' 138 | LIBS := $(shell $(FINDCMD) "$(ESP_LIBS) $(HOME)/Arduino/libraries" $(SKETCH) ../../src/*.cpp ../../src/*.h) 139 | ifeq ($(LIBS),) 140 | # No dependencies found 141 | LIBS = /dev/null 142 | endif 143 | endif 144 | IGNORE_PATTERN := $(foreach dir,$(EXCLUDE_DIRS),$(dir)/%) 145 | SKETCH_DIR = $(dir $(SKETCH)) 146 | USER_INC := $(filter-out $(IGNORE_PATTERN),$(shell find -L $(SKETCH_DIR) $(LIBS) -name "*.h")) 147 | USER_SRC := $(SKETCH) $(filter-out $(IGNORE_PATTERN),$(shell find -L $(SKETCH_DIR) $(LIBS) -name "*.S" -o -name "*.c" -o -name "*.cpp")) 148 | # Object file suffix seems to be significant for the linker... 149 | USER_OBJ := $(subst .ino,_.cpp,$(patsubst %,$(BUILD_DIR)/%$(OBJ_EXT),$(notdir $(USER_SRC)))) 150 | USER_DIRS := $(sort $(dir $(USER_SRC))) 151 | USER_INC_DIRS := $(sort $(dir $(USER_INC))) 152 | 153 | # Use first flash definition for the board as default 154 | FLASH_DEF ?= $(shell cat $(ESP_ROOT)/boards.txt | perl -e 'while (<>) {if (/^$(BOARD)\.menu\.FlashSize\.([^\.]+)=/){ print "$$1"; exit;}} print "NA";') 155 | 156 | # The actual build commands are to be extracted from the Arduino description files 157 | ARDUINO_MK = $(BUILD_DIR)/arduino.mk 158 | ARDUINO_DESC := $(shell find $(ESP_ROOT) -maxdepth 1 -name "*.txt" | sort) 159 | $(ARDUINO_MK): $(ARDUINO_DESC) $(MAKEFILE_LIST) | $(BUILD_DIR) 160 | perl -e "$$PARSE_ARDUINO" $(BOARD) $(FLASH_DEF) $(ARDUINO_EXTRA_DESC) $(ARDUINO_DESC) >$(ARDUINO_MK) 161 | 162 | -include $(ARDUINO_MK) 163 | 164 | # Compilation directories and path 165 | INCLUDE_DIRS += $(CORE_DIR) $(ESP_ROOT)/variants/$(INCLUDE_VARIANT) $(BUILD_DIR) 166 | C_INCLUDES := $(foreach dir,$(INCLUDE_DIRS) $(USER_INC_DIRS),-I$(dir)) 167 | VPATH += $(shell find $(CORE_DIR) -type d) $(USER_DIRS) 168 | 169 | # Automatically generated build information data 170 | # Makes the build date and git descriptions at the actual build event available as string constants in the program 171 | BUILD_INFO_H = $(BUILD_DIR)/buildinfo.h 172 | BUILD_INFO_CPP = $(BUILD_DIR)/buildinfo.c++ 173 | BUILD_INFO_OBJ = $(BUILD_INFO_CPP)$(OBJ_EXT) 174 | 175 | $(BUILD_INFO_H): | $(BUILD_DIR) 176 | echo "typedef struct { const char *date, *time, *src_version, *env_version;} _tBuildInfo; extern _tBuildInfo _BuildInfo;" >$@ 177 | 178 | # Build rules for the different source file types 179 | $(BUILD_DIR)/%.cpp$(OBJ_EXT): %.cpp $(BUILD_INFO_H) $(ARDUINO_MK) 180 | echo $(' >$(BUILD_INFO_CPP) 208 | echo '_tBuildInfo _BuildInfo = {"$(BUILD_DATE)","$(BUILD_TIME)","$(SRC_GIT_VERSION)","$(ESP_ARDUINO_VERSION)"};' >>$(BUILD_INFO_CPP) 209 | $(CPP_COM) $(BUILD_INFO_CPP) -o $(BUILD_INFO_OBJ) 210 | $(LD_COM) 211 | $(GEN_PART_COM) 212 | $(ELF2BIN_COM) 213 | $(SIZE_COM) | perl -e "$$MEM_USAGE" "$(MEM_FLASH)" "$(MEM_RAM)" 214 | ifneq ($(FLASH_INFO),) 215 | printf "Flash size: $(FLASH_INFO)\n\n" 216 | endif 217 | perl -e 'print "Build complete. Elapsed time: ", time()-$(START_TIME), " seconds\n\n"' 218 | 219 | upload flash: all 220 | $(UPLOAD_COM) 221 | 222 | ota: all 223 | $(OTA_TOOL) -i $(ESP_ADDR) -p $(ESP_PORT) -a $(ESP_PWD) -f $(MAIN_EXE) 224 | 225 | http: all 226 | $(HTTP_TOOL) --verbose -F image=@$(MAIN_EXE) --user $(HTTP_USR):$(HTTP_PWD) http://$(HTTP_ADDR)$(HTTP_URI) 227 | echo "\n" 228 | 229 | $(FS_IMAGE): $(wildcard $(FS_DIR)/*) 230 | ifneq ($(CHIP),esp32) 231 | echo Generating filesystem image: $(FS_IMAGE) 232 | $(MKSPIFFS_COM) 233 | else 234 | echo No SPIFFS function available for $(CHIP) 235 | exit 1 236 | endif 237 | 238 | fs: $(FS_IMAGE) 239 | 240 | upload_fs flash_fs: $(FS_IMAGE) 241 | $(FS_UPLOAD_COM) 242 | 243 | FLASH_FILE ?= esp_flash.bin 244 | dump_flash: 245 | echo Dumping flash memory to file: $(FLASH_FILE) 246 | $(ESPTOOL_PY) read_flash 0 $(shell perl -e 'shift =~ /(\d+)([MK])/ || die "Invalid memory size\n";$$mem_size=$$1*1024;$$mem_size*=1024 if $$2 eq "M";print $$mem_size;' $(FLASH_DEF)) $(FLASH_FILE) 247 | 248 | restore_flash: 249 | echo Restoring flash memory from file: $(FLASH_FILE) 250 | $(ESPTOOL_PY) write_flash -fs $(shell perl -e 'shift =~ /(\d+)([MK])/ || die "Invalid memory size\n";print ($$2 eq "K" ? 2 : $$1*8);' $(FLASH_DEF))m -fm $(FLASH_MODE) -ff $(FLASH_SPEED)m 0 $(FLASH_FILE) 251 | 252 | clean: 253 | echo Removing all build files 254 | rm -rf $(BUILD_DIR)/* 255 | 256 | list_boards: 257 | echo === Available boards === 258 | cat $(ESP_ROOT)/boards.txt | perl -e 'while (<>) { if (/^(\w+)\.name=(.+)/){ print sprintf("%-20s %s\n", $$1,$$2);} }' 259 | 260 | list_lib: 261 | echo === User specific libraries === 262 | perl -e 'foreach (@ARGV) {print "$$_\n"}' "* Include directories:" $(USER_INC_DIRS) "* Library source files:" $(USER_SRC) "Foo" $(IGNORE_PATTERN) 263 | 264 | list_flash_defs: 265 | echo === Memory configurations for board: $(BOARD) === 266 | cat $(ESP_ROOT)/boards.txt | perl -e 'while (<>) { if (/^$(BOARD)\.menu\.FlashSize.([^\.]+)=(.+)/){ print sprintf("%-10s %s\n", $$1,$$2);} }' 267 | 268 | help: 269 | echo 270 | echo "Generic makefile for building Arduino esp8266 and esp32 projects" 271 | echo "This file can either be used directly or included from another makefile" 272 | echo "" 273 | echo "The following targets are available:" 274 | echo " all (default) Build the project application" 275 | echo " clean Remove all intermediate build files" 276 | echo " flash Build and and flash the project application" 277 | echo " flash_fs Build and and flash file system (when applicable)" 278 | echo " ota Build and and flash via OTA" 279 | echo " Params: ESP_ADDR, ESP_PORT and ESP_PWD" 280 | echo " http Build and and flash via http (curl)" 281 | echo " Params: HTTP_ADDR, HTTP_URI, HTTP_PWD and HTTP_USR" 282 | echo " dump_flash Dump the whole board flash memory to a file" 283 | echo " restore_flash Restore flash memory from a previously dumped file" 284 | echo " list_lib Show a list of used library files and include paths" 285 | echo "Configurable parameters:" 286 | echo " SKETCH Main source file" 287 | echo " If not specified the first sketch in current" 288 | echo " directory will be used. If none is found there," 289 | echo " a demo example will be used instead." 290 | echo " LIBS Includes in the sketch file of libraries from within" 291 | echo " the ESP Arduino directories are automatically" 292 | echo " detected. If this is not enough, define this" 293 | echo " variable with all libraries or directories needed." 294 | echo " USER_LIBS Path to user installed Arduino libraries" 295 | echo " CHIP Set to esp8266 or esp32. Default: '$(CHIP)'" 296 | echo " BOARD Name of the target board. Default: '$(BOARD)'" 297 | echo " Use 'list_boards' to get list of available ones" 298 | echo " FLASH_DEF Flash partitioning info. Default '$(FLASH_DEF)'" 299 | echo " Use 'list_flash_defs' to get list of available ones" 300 | echo " BUILD_DIR Directory for intermediate build files." 301 | echo " Default '$(BUILD_DIR)'" 302 | echo " BUILD_EXTRA_FLAGS Additional parameters for the compilation commands" 303 | echo " FS_DIR File system root directory" 304 | echo " UPLOAD_PORT Serial flashing port name. Default: '$(UPLOAD_PORT)'" 305 | echo " UPLOAD_SPEED Serial flashing baud rate. Default: '$(UPLOAD_SPEED)'" 306 | echo " FLASH_FILE File name for dump and restore flash operations" 307 | echo " Default: '$(FLASH_FILE)'" 308 | echo " VERBOSE Set to 1 to get full printout of the build" 309 | echo " SINGLE_THREAD Use only one build thread" 310 | echo 311 | 312 | $(BUILD_DIR): 313 | mkdir -p $(BUILD_DIR) 314 | 315 | .PHONY: all 316 | all: $(BUILD_DIR) $(ARDUINO_MK) $(BUILD_INFO_H) prebuild $(MAIN_EXE) 317 | 318 | prebuild: 319 | ifdef USE_PREBUILD 320 | $(PREBUILD_COM) 321 | endif 322 | 323 | # Include all available dependencies 324 | -include $(wildcard $(BUILD_DIR)/*$(DEP_EXT)) 325 | 326 | .DEFAULT_GOAL = all 327 | 328 | ifndef SINGLE_THREAD 329 | # Use multithreaded builds by default 330 | MAKEFLAGS += -j 331 | endif 332 | 333 | ifndef VERBOSE 334 | # Set silent mode as default 335 | MAKEFLAGS += --silent 336 | endif 337 | 338 | # Inline Perl scripts 339 | 340 | # Parse Arduino definitions and build commands from the descriptions 341 | define PARSE_ARDUINO 342 | my $$board = shift; 343 | my $$flashSize = shift; 344 | my %v; 345 | 346 | sub def_var { 347 | my ($$name, $$var) = @_; 348 | print "$$var ?= $$v{$$name}\n"; 349 | $$v{$$name} = "\$$($$var)"; 350 | } 351 | 352 | $$v{'runtime.platform.path'} = '$$(ESP_ROOT)'; 353 | $$v{'includes'} = '$$(C_INCLUDES)'; 354 | $$v{'runtime.ide.version'} = '10605'; 355 | $$v{'build.arch'} = '$$(CHIP)'; 356 | $$v{'build.project_name'} = '$$(MAIN_NAME)'; 357 | $$v{'build.path'} = '$$(BUILD_DIR)'; 358 | $$v{'object_files'} = '$$^ $$(BUILD_INFO_OBJ)'; 359 | 360 | foreach my $$fn (@ARGV) { 361 | open($$f, $$fn) || die "Failed to open: $$fn\n"; 362 | while (<$$f>) { 363 | next unless /^(\w[\w\-\.]+)=(.*)/; 364 | my ($$key, $$val) =($$1, $$2); 365 | $$board_defined = 1 if $$key eq "$$board.name"; 366 | $$key =~ s/$$board\.menu\.FlashSize\.$$flashSize\.//; 367 | $$key =~ s/$$board\.menu\.FlashFreq\.[^\.]+\.//; 368 | $$key =~ s/$$board\.menu\.UploadSpeed\.[^\.]+\.//; 369 | $$key =~ s/^$$board\.//; 370 | $$v{$$key} ||= $$val; 371 | } 372 | close($$f); 373 | } 374 | $$v{'runtime.tools.xtensa-lx106-elf-gcc.path'} ||= '$$(COMP_PATH)'; 375 | $$v{'runtime.tools.esptool.path'} ||= '$$(ESPTOOL_PATH)'; 376 | $$v{'runtime.tools.mkspiffs.path'} ||= '$$(MKSPIFFS_PATH)'; 377 | 378 | die "* Uknown board $$board\n" unless $$board_defined; 379 | 380 | print "# Board definitions\n"; 381 | def_var('build.f_cpu', 'F_CPU'); 382 | def_var('build.flash_mode', 'FLASH_MODE'); 383 | def_var('build.flash_freq', 'FLASH_SPEED'); 384 | def_var('upload.resetmethod', 'UPLOAD_RESET'); 385 | def_var('upload.speed', 'UPLOAD_SPEED'); 386 | def_var('compiler.warning_flags', 'COMP_WARNINGS'); 387 | $$v{'upload.verbose'} = '$$(UPLOAD_VERB)'; 388 | $$v{'serial.port'} = '$$(UPLOAD_PORT)'; 389 | $$v{'recipe.objcopy.hex.pattern'} =~ s/[^"]+\/bootloaders\/eboot\/eboot.elf/\$$(BOOT_LOADER)/; 390 | $$v{'tools.esptool.upload.pattern'} =~ s/\{(cmd|path)\}/\{tools.esptool.$$1\}/g; 391 | $$v{'compiler.cpreprocessor.flags'} .= " \$$(C_PRE_PROC_FLAGS)"; 392 | $$v{'build.extra_flags'} .= " \$$(BUILD_EXTRA_FLAGS)"; 393 | 394 | foreach my $$key (sort keys %v) { 395 | while ($$v{$$key} =~/\{/) { 396 | $$v{$$key} =~ s/\{([\w\-\.]+)\}/$$v{$$1}/; 397 | $$v{$$key} =~ s/""//; 398 | } 399 | $$v{$$key} =~ s/ -o $$//; 400 | $$v{$$key} =~ s/(-D\w+=)"([^"]+)"/$$1\\"$$2\\"/g; 401 | } 402 | 403 | print "INCLUDE_VARIANT = $$v{'build.variant'}\n"; 404 | print "# Commands\n"; 405 | print "C_COM=$$v{'recipe.c.o.pattern'}\n"; 406 | print "CPP_COM=$$v{'recipe.cpp.o.pattern'}\n"; 407 | print "S_COM=$$v{'recipe.S.o.pattern'}\n"; 408 | print "AR_COM=$$v{'recipe.ar.pattern'}\n"; 409 | print "LD_COM=$$v{'recipe.c.combine.pattern'}\n"; 410 | print "GEN_PART_COM=$$v{'recipe.objcopy.eep.pattern'}\n"; 411 | print "ELF2BIN_COM=$$v{'recipe.objcopy.hex.pattern'}\n"; 412 | print "SIZE_COM=$$v{'recipe.size.pattern'}\n"; 413 | my $$flash_size = sprintf("0x%X", hex($$v{'build.spiffs_end'})-hex($$v{'build.spiffs_start'})); 414 | print "MKSPIFFS_COM=$$v{'tools.mkspiffs.path'}/$$v{'tools.mkspiffs.cmd'} -b $$v{'build.spiffs_blocksize'} -s $$flash_size -c \$$(FS_DIR) \$$(FS_IMAGE)\n"; 415 | print "UPLOAD_COM=$$v{'tools.esptool.upload.pattern'}\n"; 416 | my $$fs_upload_com = $$v{'tools.esptool.upload.pattern'}; 417 | $$fs_upload_com =~ s/(.+ -ca) .+/$$1 $$v{'build.spiffs_start'} -cf \$$(FS_IMAGE)/; 418 | print "FS_UPLOAD_COM=$$fs_upload_com\n"; 419 | my $$val = $$v{'recipe.hooks.core.prebuild.1.pattern'}; 420 | $$val =~ s/bash -c "(.+)"/$$1/; 421 | $$val =~ s/(#define .+0x)(\`)/"\\$$1\"$$2/; 422 | $$val =~ s/(\\)//; 423 | print "PREBUILD_COM=$$val\n"; 424 | print "MEM_FLASH=$$v{'recipe.size.regex'}\n"; 425 | print "MEM_RAM=$$v{'recipe.size.regex.data'}\n"; 426 | print "FLASH_INFO=$$v{'menu.FlashSize.' . $$flashSize}\n" 427 | endef 428 | export PARSE_ARDUINO 429 | 430 | # Convert memory information 431 | define MEM_USAGE 432 | $$fp = shift; 433 | $$rp = shift; 434 | while (<>) { 435 | $$r += $$1 if /$$rp/; 436 | $$f += $$1 if /$$fp/; 437 | } 438 | print "\nMemory usage\n"; 439 | print sprintf(" %-6s %6d bytes\n" x 2 ."\n", "Ram:", $$r, "Flash:", $$f); 440 | endef 441 | export MEM_USAGE 442 | -------------------------------------------------------------------------------- /examples/ESP8266MeshSensor/README.md: -------------------------------------------------------------------------------- 1 | # ESP8266MeshSensor 2 | 3 | This example is designed to use the ESP8266MQTTMesh library with a Sonoff Relay 4 | (it has only been tested with the SonoffPOW, but should work with other variants 5 | with minor changes) 6 | 7 | ## Required Libraries 8 | The following libraries are required to build ths example 9 | * ESP8266MQTTMesh 10 | * HLW8012 (if using a Sonoff POW) 11 | * OneWire (if using DS18B20) 12 | * DallasTemperature (is using DS18B20) 13 | 14 | ## Compiling 15 | The collowing configurations are needed before compiling: 16 | * copy credentials.h.example to credentials.h and update as needed 17 | * ensure the relevant pins are defined if you have a DS18B20 or HLW8012 18 | 19 | ## MQTT Commands 20 | 21 | | Topic | Message | Description | 22 | |---------------------|-------------|-------------| 23 | | \/heartbeat | \ | How often to send current status in millseconds (default 60000) | 24 | | \/expectedpower | \ | Calculate HLW8012 calibration based on current power | 25 | | \/expectedvoltage | \ | Calculate HLW8012 calibration based on current voltage | 26 | | \/expectedcurrent | \ | Calculate HLW8012 calibration based on current current | 27 | | \/resetpower | \ | Reset all of the HLW8012 calibration values | 28 | -------------------------------------------------------------------------------- /examples/ESP8266MeshSensor/config.mk: -------------------------------------------------------------------------------- 1 | FLASH_DEF = 2M 2 | USER_LIBS = ${HOME}/Arduino/libraries/ 3 | CPP_EXTRA = -Wall 4 | BUILD_EXTRA_FLAGS = "-DMQTT_MAX_PACKET_SIZE=1152" 5 | -------------------------------------------------------------------------------- /examples/ESP8266MeshSensor/credentials.h.example: -------------------------------------------------------------------------------- 1 | #define NETWORK_LIST { \ 2 | "ssid 1", \ 3 | "ssid 2", \ 4 | "", \ 5 | } 6 | #define NETWORK_PASSWORD "network password" 7 | #define MESH_PASSWORD "esp8266_sensor_mesh" 8 | #define BASE_SSID "mesh_esp8266-" 9 | #define MQTT_SERVER "MQTT Server IP Address" 10 | #define MQTT_PORT 1883 11 | #define MESH_PORT 1884 12 | 13 | -------------------------------------------------------------------------------- /examples/ESP8266MeshSensor/platformio.ini: -------------------------------------------------------------------------------- 1 | # 2 | # Example PlatformIO configuration file for SSL and non-SSL builds. 3 | # 4 | # Before you will be able to build the SSL version of this project, you will 5 | # need to explicitly install the espressif8266_stage platform. 6 | # 7 | # To perform this installation, refer to step 1 of: 8 | # http://docs.platformio.org/en/latest/platforms/espressif8266.html#using-arduino-framework-with-staging-version 9 | 10 | [platformio] 11 | env_default = nossl 12 | 13 | [common] 14 | framework = arduino 15 | lib_deps = ESP8266MQTTMesh 16 | lib_deps_external = 17 | HLW8012 18 | OneWire 19 | DallasTemperature 20 | 21 | [env:nossl] 22 | platform = espressif8266@~1.6.0 23 | framework = arduino 24 | board = esp01_1m 25 | lib_deps = 26 | ${common.lib_deps} 27 | ${common.lib_deps_external} 28 | -------------------------------------------------------------------------------- /examples/ESP8266MeshSensor/src/ESP8266MeshSensor.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 PhracturedBlue 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | * 17 | * HLW8012 code Copyright (C) 2016-2017 by Xose Pérez 18 | */ 19 | 20 | /* Sonoff POW w/ DS18B20 attached to GPIO2(SDA) */ 21 | #define GREEN_LED 15 //MTDO 22 | #define RELAY 12 //MTDI 23 | #define BUTTON 0 //GPIO0 24 | #define DS18B20 2 //GPIO2 25 | #define HLW8012_SEL 5 //GPIO5 26 | #define HLW8012_CF 14 //MTMS 27 | #define HLW8012_CF1 13 //MTCK 28 | 29 | /* See credentials.h.examle for contents of credentials.h */ 30 | #include "credentials.h" 31 | #include "capabilities.h" 32 | #include 33 | #include 34 | #if HAS_DS18B20 35 | #include 36 | #include 37 | #endif 38 | #if HAS_HLW8012 39 | #include 40 | #endif 41 | 42 | #include 43 | 44 | #if HAS_DS18B20 && HAS_HLW8012 45 | #define FIRMWARE_ID 0x4455 46 | #elif HAS_DS18B20 47 | #define FIRMWARE_ID 0x4454 48 | #elif HAS_HLW8012 49 | #define FIRMWARE_ID 0x4453 50 | #else 51 | #define FIRMWARE_ID 0x4452 52 | #endif 53 | 54 | #define FIRMWARE_VER "0.8.1" 55 | //const char* networks[] = NETWORK_LIST; 56 | const wifi_conn networks[] = { 57 | WIFI_CONN("foo", NETWORK_PASSWORD, NULL, false), 58 | WIFI_CONN("bar", NETWORK_PASSWORD, "XX:XX:XX:XX:XX:XX", true), 59 | NULL 60 | }; 61 | const char* mesh_password = MESH_PASSWORD; 62 | const char* mqtt_server = MQTT_SERVER; 63 | 64 | #if HAS_DS18B20 65 | OneWire oneWire(DS18B20); 66 | DallasTemperature ds18b20(&oneWire); 67 | DeviceAddress ds18b20Address; 68 | #endif 69 | 70 | #if HAS_HLW8012 71 | #define HLW8012_CURRENT_R 0.001 72 | #define HLW8012_VOLTAGE_R_UP ( 5 * 470000 ) // Real: 2280k 73 | #define HLW8012_VOLTAGE_R_DOWN ( 1000 ) // Real 1.009k 74 | #define HLW8012_UPDATE_INTERVAL 2000 75 | #define HLW8012_MIN_CURRENT 0.05 76 | #define HLW8012_MIN_POWER 10 77 | HLW8012 hlw8012; 78 | unsigned int power_sum; 79 | unsigned int voltage_sum; 80 | double current_sum; 81 | double energy; //in Watt-Seconds 82 | unsigned long power_sample_count = 0; 83 | bool hlw8012Enabled = false; 84 | 85 | void hlw8012_cf1_interrupt(); 86 | void hlw8012_cf_interrupt(); 87 | void hlw8012_enable_interrupts(bool enabled); 88 | unsigned int hlw8012_getActivePower(); 89 | double hlw8012_getCurrent(); 90 | unsigned int hlw8012_getVoltage(); 91 | #endif 92 | 93 | ESP8266MQTTMesh mesh = ESP8266MQTTMesh::Builder(networks, mqtt_server) 94 | .setVersion(FIRMWARE_VER, FIRMWARE_ID) 95 | .setMeshPassword(mesh_password) 96 | .build(); 97 | 98 | bool relayState = false; 99 | bool stateChanged = false; 100 | int heartbeat = 60000; 101 | float temperature = 0.0; 102 | 103 | void read_config(); 104 | void save_config(); 105 | void callback(const char *topic, const char *msg); 106 | String build_json(); 107 | 108 | void setup() { 109 | pinMode(GREEN_LED, OUTPUT); 110 | pinMode(RELAY, OUTPUT); 111 | pinMode(BUTTON, INPUT); 112 | Serial.begin(115200); 113 | delay(5000); 114 | mesh.setCallback(callback); 115 | mesh.begin(); 116 | #if HAS_DS18B20 117 | ds18b20.begin(); 118 | ds18b20.getAddress(ds18b20Address, 0); 119 | ds18b20.setWaitForConversion(false); 120 | ds18b20.requestTemperatures(); 121 | #endif 122 | Serial.println("HLW8012 start"); 123 | #if HAS_HLW8012 124 | hlw8012.begin(HLW8012_CF, HLW8012_CF1, HLW8012_SEL, HIGH, true); 125 | hlw8012.setResistors(HLW8012_CURRENT_R, HLW8012_VOLTAGE_R_UP, HLW8012_VOLTAGE_R_DOWN); 126 | #endif 127 | Serial.println("HLW8012 end"); 128 | //mesh.setup will initialize the filesystem 129 | if (SPIFFS.exists("/config")) { 130 | read_config(); 131 | } 132 | Serial.println("config end"); 133 | digitalWrite(RELAY, relayState); 134 | } 135 | 136 | void loop() { 137 | static unsigned long pressed = 0; 138 | static unsigned long lastSend = 0; 139 | static bool needToSend = false; 140 | 141 | unsigned long now = millis(); 142 | 143 | #if HAS_DS18B20 144 | if (ds18b20.isConversionAvailable(ds18b20Address)) { 145 | temperature = ds18b20.getTempF(ds18b20Address); 146 | ds18b20.requestTemperatures(); 147 | } 148 | #endif 149 | 150 | #if HAS_HLW8012 151 | if (! hlw8012Enabled && mesh.connected()) { 152 | hlw8012_enable_interrupts(true); 153 | } else if (hlw8012Enabled && ! mesh.connected()) { 154 | hlw8012_enable_interrupts(false); 155 | } 156 | static unsigned long last_hlw8012_update = 0; 157 | if (now - last_hlw8012_update > HLW8012_UPDATE_INTERVAL) { 158 | static unsigned int power[3] = {0}; 159 | static unsigned int voltage[3] = {0}; 160 | static double current[3] = {0}; 161 | for (int i = 0; i < 2; i++) { 162 | power[i] = power[i+1]; 163 | voltage[i] = voltage[i+1]; 164 | current[i] = current[i+1]; 165 | } 166 | power[2] = hlw8012_getActivePower(); 167 | voltage[2] = hlw8012_getVoltage(); 168 | current[2] = hlw8012_getCurrent(); 169 | 170 | //Spike removal 171 | if (power[1] > 0 && power[0] == 0 && power[2] == 0) { 172 | power[1] = 0; 173 | } 174 | if (current[1] > 0 && current[0] == 0 && current[2] == 0) { 175 | current[1] = 0; 176 | } 177 | if (voltage[1] > 0 && voltage[0] == 0 && voltage[2] == 0) { 178 | voltage[1] = 0; 179 | } 180 | power_sum += power[0]; 181 | current_sum += current[0]; 182 | voltage_sum += voltage[0]; 183 | energy += 1.0 * power[0] * (now - last_hlw8012_update) / 1000.0; 184 | power_sample_count++; 185 | last_hlw8012_update = now; 186 | } 187 | #endif 188 | if (! digitalRead(BUTTON)) { 189 | if(pressed == 0) { 190 | relayState = ! relayState; 191 | digitalWrite(RELAY, relayState); 192 | stateChanged = true; 193 | } 194 | pressed = now; 195 | } else if (pressed && now - pressed > 100) { 196 | pressed = 0; 197 | } 198 | if (stateChanged) { 199 | save_config(); 200 | needToSend = true; 201 | stateChanged = false; 202 | } else if (now - lastSend > heartbeat) { 203 | needToSend = true; 204 | } 205 | if (! mesh.connected()) { 206 | return; 207 | } 208 | if (needToSend) { 209 | lastSend = now; 210 | String data = build_json(); 211 | #if HAS_HLW8012 212 | power_sum = 0; 213 | current_sum = 0; 214 | voltage_sum = 0; 215 | power_sample_count = 0; 216 | #endif 217 | mesh.publish("status", data.c_str()); 218 | needToSend = false; 219 | } 220 | } 221 | 222 | void callback(const char *topic, const char *msg) { 223 | if (0 == strcmp(topic, "heartbeat")) { 224 | unsigned int hb = strtoul(msg, NULL, 10); 225 | if (hb > 10000) { 226 | heartbeat = hb; 227 | save_config(); 228 | } 229 | } 230 | else if (0 == strcmp(topic, "state")) { 231 | bool nextState = strtoul(msg, NULL, 10) ? true : false; 232 | if (relayState != nextState) { 233 | relayState = nextState; 234 | digitalWrite(RELAY, relayState); 235 | stateChanged = true; 236 | } 237 | } 238 | #if HAS_HLW8012 239 | else if (0 == strcmp(topic, "expectedpower")) { 240 | int pow = atoi(msg); 241 | if (pow > 0) { 242 | hlw8012.expectedActivePower(pow); 243 | save_config(); 244 | } 245 | } 246 | else if (0 == strcmp(topic, "expectedvoltage")) { 247 | int volt = atoi(msg); 248 | if (volt > 0) { 249 | hlw8012.expectedVoltage(volt); 250 | save_config(); 251 | } 252 | } 253 | else if (0 == strcmp(topic, "expectedcurrent")) { 254 | double current = atof(msg); 255 | if (current > 0) { 256 | hlw8012.expectedCurrent(current); 257 | save_config(); 258 | } 259 | } 260 | else if (0 == strcmp(topic, "resetpower")) { 261 | int state = atoi(msg); 262 | if (state > 0) { 263 | hlw8012.resetMultipliers(); 264 | save_config(); 265 | } 266 | } 267 | #endif //HAS_HLW8012 268 | } 269 | 270 | String build_json() { 271 | String msg = "{"; 272 | msg += " \"relay\":\"" + String(relayState ? "ON" : "OFF") + "\""; 273 | #if HAS_DS18B20 274 | msg += ", \"temp\":" + String(temperature, 2); 275 | #endif 276 | #if HAS_HLW8012 277 | double count = power_sample_count ? power_sample_count : 1; 278 | double power = (double)power_sum / count; 279 | double current = (double)current_sum / count; 280 | double voltage = (double)voltage_sum / count; 281 | double apparent= voltage * current; 282 | double pfactor = (apparent > 0) ? 100 * power / apparent : 100; 283 | if (pfactor > 100) { 284 | pfactor = 100; 285 | } 286 | msg += ", \"power\":" + String(power, 3); 287 | msg += ", \"current\":" + String(current, 3); 288 | msg += ", \"voltage\":" + String(voltage, 3); 289 | msg += ", \"pf\":" + String(pfactor, 3); 290 | msg += ", \"energy\":" + String(energy / 3600, 3); //Watt-Hours 291 | #endif 292 | msg += "}"; 293 | return msg; 294 | } 295 | 296 | void read_config() { 297 | File f = SPIFFS.open("/config", "r"); 298 | if (! f) { 299 | Serial.println("Failed to read config"); 300 | return; 301 | } 302 | while(f.available()) { 303 | char s[32]; 304 | char key[32]; 305 | const char *value; 306 | s[f.readBytesUntil('\n', s, sizeof(s)-1)] = 0; 307 | if (! ESP8266MQTTMesh::keyValue(s, '=', key, sizeof(key), &value)) { 308 | continue; 309 | } 310 | if (0 == strcmp(key, "RELAY")) { 311 | relayState = value[0] == '0' ? 0 : 1; 312 | } 313 | else if (0 == strcmp(key, "HEARTBEAT")) { 314 | heartbeat = atoi(value); 315 | if (heartbeat < 1000) { 316 | heartbeat = 1000; 317 | } else if (heartbeat > 60 * 60 * 1000) { 318 | heartbeat = 5 * 60 * 1000; 319 | } 320 | } 321 | #if HAS_HLW8012 322 | else if (0 == strcmp(key, "hlw8012PowerMult")) { 323 | double dbl = atof(value); 324 | if (dbl > 0) hlw8012.setPowerMultiplier(dbl); 325 | 326 | } 327 | else if (0 == strcmp(key, "hlw8012CurrentMult")) { 328 | double dbl = atof(value); 329 | if (dbl > 0) hlw8012.setCurrentMultiplier(dbl); 330 | } 331 | else if (0 == strcmp(key, "hlw8012VoltageMult")) { 332 | double dbl = atof(value); 333 | if (dbl > 0) hlw8012.setVoltageMultiplier(dbl); 334 | } 335 | #endif //HAS_HLW8012 336 | } 337 | f.close(); 338 | } 339 | 340 | void save_config() { 341 | File f = SPIFFS.open("/config", "w"); 342 | if (! f) { 343 | Serial.println("Failed to write config"); 344 | return; 345 | } 346 | f.print("RELAY=" + String(relayState ? "1" : "0") + "\n"); 347 | f.print("HEARTBEAT=" + String(heartbeat) + "\n"); 348 | #if HAS_HLW8012 349 | f.print("hlw8012PowerMult=" + String(hlw8012.getPowerMultiplier())); 350 | f.print("hlw8012CurrentMult=" + String(hlw8012.getCurrentMultiplier())); 351 | f.print("hlw8012VoltageMult=" + String(hlw8012.getVoltageMultiplier())); 352 | #endif 353 | f.close(); 354 | } 355 | 356 | 357 | // When using interrupts we have to call the library entry point 358 | // whenever an interrupt is triggered 359 | #if HAS_HLW8012 360 | void hlw8012_cf1_interrupt() { 361 | hlw8012.cf1_interrupt(); 362 | } 363 | 364 | void hlw8012_cf_interrupt() { 365 | hlw8012.cf_interrupt(); 366 | } 367 | void hlw8012_enable_interrupts(bool enabled) { 368 | if (enabled) { 369 | attachInterrupt(HLW8012_CF1, hlw8012_cf1_interrupt, CHANGE); 370 | attachInterrupt(HLW8012_CF, hlw8012_cf_interrupt, CHANGE); 371 | hlw8012Enabled = true; 372 | } else { 373 | detachInterrupt(HLW8012_CF1); 374 | detachInterrupt(HLW8012_CF); 375 | hlw8012Enabled = false; 376 | } 377 | } 378 | unsigned int hlw8012_getActivePower() { 379 | unsigned int power = hlw8012.getActivePower(); 380 | if (power < HLW8012_MIN_POWER) power = 0; 381 | return power; 382 | } 383 | 384 | double hlw8012_getCurrent() { 385 | double current = hlw8012.getCurrent(); 386 | if (current < HLW8012_MIN_CURRENT) current = 0; 387 | return current; 388 | } 389 | 390 | unsigned int hlw8012_getVoltage() { 391 | return hlw8012.getVoltage(); 392 | } 393 | #endif 394 | -------------------------------------------------------------------------------- /examples/ESP8266MeshSensor/src/capabilities.h: -------------------------------------------------------------------------------- 1 | #ifndef _CAPABILITIES_H_ 2 | #define _CAPABILITIES_H_ 3 | 4 | #ifdef DS18B20 5 | #define HAS_DS18B20 1 6 | #else 7 | #define HAS_DS18B20 0 8 | #endif 9 | 10 | #if defined(HLW8012_SEL) && defined(HLW8012_CF) && defined (HLW8012_CF1) 11 | #define HAS_HLW8012 1 12 | #else 13 | #define HAS_HLW8012 0 14 | #endif 15 | #endif //_CAPABILITIES_H_ 16 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ESP8266MQTTMesh", 3 | "keywords": "iot, home, automation, async, mqtt, client, esp8266, mesh, ota", 4 | "description": "An Arduino for ESP8266 self-assembling Mesh network built around the MQTT protocol supporting OTA", 5 | "version": "1.0.4", 6 | "frameworks": "arduino", 7 | "platforms": ["espressif8266", "espressif32"], 8 | "authors": 9 | { 10 | "name": "PhracturedBlue", 11 | "url": "https://github.com/PhracturedBlue" 12 | }, 13 | "repository": 14 | { 15 | "type": "git", 16 | "url": "https://github.com/PhracturedBlue/ESP8266MQTTMesh.git" 17 | }, 18 | "dependencies": [ 19 | { 20 | "name": "ESPAsyncTCP", 21 | "version": "^1.1.3", 22 | "platforms": "espressif8266" 23 | }, 24 | { 25 | "name": "AsyncMqttClient", 26 | "version": "^0.8.1", 27 | "platforms": "espressif8266" 28 | }, 29 | { 30 | "name": "AsyncTCP", 31 | "platforms": "espressif32" 32 | }, 33 | { 34 | "name": "Ticker-esp32", 35 | "platforms": "espressif32" 36 | }, 37 | { 38 | "name": "AsyncMqttClient", 39 | "version": "https://github.com/marvinroger/async-mqtt-client#101277d", 40 | "platforms": "espressif32" 41 | } 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=ESP8266 MQTT Mesh 2 | version=1.0.4 3 | author=PhracturedBlue 4 | maintainer=PhracturedBlue 5 | sentence=Self-assembling Mesh network built around the MQTT protocol supporting OTA 6 | paragraph=Self-assembling mesh network built around the MQTT protocol for the ESP8266 and ESP32 with OTA support 7 | category=Communication 8 | url=https://github.com/PhracturedBlue/ESP8266MQTTMesh 9 | architectures=esp8266,esp32 10 | includes=ESP8266MQTTMesh.h 11 | -------------------------------------------------------------------------------- /src/Base64.cpp: -------------------------------------------------------------------------------- 1 | /*Copyright (C) 2013 Adam Rudd 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | */ 9 | 10 | #include "Base64.h" 11 | #include 12 | const char PROGMEM b64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 13 | "abcdefghijklmnopqrstuvwxyz" 14 | "0123456789+/"; 15 | 16 | /* 'Private' declarations */ 17 | inline void a3_to_a4(unsigned char * a4, unsigned char * a3); 18 | inline void a4_to_a3(unsigned char * a3, unsigned char * a4); 19 | inline unsigned char b64_lookup(char c); 20 | 21 | int base64_encode(char *output, const char *input, int inputLen) { 22 | int i = 0, j = 0; 23 | int encLen = 0; 24 | unsigned char a3[3]; 25 | unsigned char a4[4]; 26 | 27 | while (inputLen--) { 28 | a3[i++] = *(input++); 29 | if (i == 3) { 30 | a3_to_a4(a4, a3); 31 | 32 | for (i = 0; i < 4; i++) { 33 | output[encLen++] = pgm_read_byte(&b64_alphabet[a4[i]]); 34 | } 35 | 36 | i = 0; 37 | } 38 | } 39 | 40 | if (i) { 41 | for (j = i; j < 3; j++) { 42 | a3[j] = '\0'; 43 | } 44 | 45 | a3_to_a4(a4, a3); 46 | 47 | for (j = 0; j < i + 1; j++) { 48 | output[encLen++] = pgm_read_byte(&b64_alphabet[a4[j]]); 49 | } 50 | 51 | while ((i++ < 3)) { 52 | output[encLen++] = '='; 53 | } 54 | } 55 | output[encLen] = '\0'; 56 | return encLen; 57 | } 58 | 59 | int base64_decode(char * output, const char * input, int inputLen) { 60 | int i = 0, j = 0; 61 | int decLen = 0; 62 | unsigned char a3[3]; 63 | unsigned char a4[4]; 64 | 65 | 66 | while (inputLen--) { 67 | if (*input == '=') { 68 | break; 69 | } 70 | 71 | a4[i++] = *(input++); 72 | if (i == 4) { 73 | for (i = 0; i < 4; i++) { 74 | a4[i] = b64_lookup(a4[i]); 75 | } 76 | 77 | a4_to_a3(a3, a4); 78 | 79 | for (i = 0; i < 3; i++) { 80 | output[decLen++] = a3[i]; 81 | } 82 | i = 0; 83 | } 84 | } 85 | 86 | if (i) { 87 | for (j = i; j < 4; j++) { 88 | a4[j] = '\0'; 89 | } 90 | 91 | for (j = 0; j < 4; j++) { 92 | a4[j] = b64_lookup(a4[j]); 93 | } 94 | 95 | a4_to_a3(a3, a4); 96 | 97 | for (j = 0; j < i - 1; j++) { 98 | output[decLen++] = a3[j]; 99 | } 100 | } 101 | //output[decLen] = '\0'; was a verry bad Idea, because it causes an Overflow in decoding the MD5 Sum and writing String Terminators in the executed Flash by an OTA Update 102 | return decLen; 103 | } 104 | 105 | int base64_enc_len(int plainLen) { 106 | int n = plainLen; 107 | return (n + 2 - ((n + 2) % 3)) / 3 * 4; 108 | } 109 | 110 | int base64_dec_len(const char * input, int inputLen) { 111 | int i = 0; 112 | int numEq = 0; 113 | for (i = inputLen - 1; input[i] == '='; i--) { 114 | numEq++; 115 | } 116 | 117 | return ((6 * inputLen) / 8) - numEq; 118 | } 119 | 120 | inline void a3_to_a4(unsigned char * a4, unsigned char * a3) { 121 | a4[0] = (a3[0] & 0xfc) >> 2; 122 | a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); 123 | a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); 124 | a4[3] = (a3[2] & 0x3f); 125 | } 126 | 127 | inline void a4_to_a3(unsigned char * a3, unsigned char * a4) { 128 | a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); 129 | a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); 130 | a3[2] = ((a4[2] & 0x3) << 6) + a4[3]; 131 | } 132 | 133 | inline unsigned char b64_lookup(char c) { 134 | if (c >= 'A' && c <= 'Z') return c - 'A'; 135 | if (c >= 'a' && c <= 'z') return c - 71; 136 | if (c >= '0' && c <= '9') return c + 4; 137 | if (c == '+') return 62; 138 | if (c == '/') return 63; 139 | return -1; 140 | } 141 | -------------------------------------------------------------------------------- /src/Base64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Adam Rudd. 3 | * See LICENSE for more information 4 | 5 | 6 | 7 | 8 | Copyright (C) 2013 Adam Rudd 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | */ 17 | #ifndef _BASE64_H 18 | #define _BASE64_H 19 | 20 | /* b64_alphabet: 21 | * Description: Base64 alphabet table, a mapping between integers 22 | * and base64 digits 23 | * Notes: This is an extern here but is defined in Base64.c 24 | */ 25 | extern const char b64_alphabet[]; 26 | 27 | /* base64_encode: 28 | * Description: 29 | * Encode a string of characters as base64 30 | * Parameters: 31 | * output: the output buffer for the encoding, stores the encoded string 32 | * input: the input buffer for the encoding, stores the binary to be encoded 33 | * inputLen: the length of the input buffer, in bytes 34 | * Return value: 35 | * Returns the length of the encoded string 36 | * Requirements: 37 | * 1. output must not be null or empty 38 | * 2. input must not be null 39 | * 3. inputLen must be greater than or equal to 0 40 | */ 41 | int base64_encode(char *output, const char *input, int inputLen); 42 | 43 | /* base64_decode: 44 | * Description: 45 | * Decode a base64 encoded string into bytes 46 | * Parameters: 47 | * output: the output buffer for the decoding, 48 | * stores the decoded binary 49 | * input: the input buffer for the decoding, 50 | * stores the base64 string to be decoded 51 | * inputLen: the length of the input buffer, in bytes 52 | * Return value: 53 | * Returns the length of the decoded string 54 | * Requirements: 55 | * 1. output must not be null or empty 56 | * 2. input must not be null 57 | * 3. inputLen must be greater than or equal to 0 58 | */ 59 | int base64_decode(char *output, const char *input, int inputLen); 60 | 61 | /* base64_enc_len: 62 | * Description: 63 | * Returns the length of a base64 encoded string whose decoded 64 | * form is inputLen bytes long 65 | * Parameters: 66 | * inputLen: the length of the decoded string 67 | * Return value: 68 | * The length of a base64 encoded string whose decoded form 69 | * is inputLen bytes long 70 | * Requirements: 71 | * None 72 | */ 73 | int base64_enc_len(int inputLen); 74 | 75 | /* base64_dec_len: 76 | * Description: 77 | * Returns the length of the decoded form of a 78 | * base64 encoded string 79 | * Parameters: 80 | * input: the base64 encoded string to be measured 81 | * inputLen: the length of the base64 encoded string 82 | * Return value: 83 | * Returns the length of the decoded form of a 84 | * base64 encoded string 85 | * Requirements: 86 | * 1. input must not be null 87 | * 2. input must be greater than or equal to zero 88 | */ 89 | int base64_dec_len(const char *input, int inputLen); 90 | 91 | #endif // _BASE64_H 92 | -------------------------------------------------------------------------------- /src/ESP8266MQTTMesh.h: -------------------------------------------------------------------------------- 1 | #ifndef _ESP8266MQTTMESH_H_ 2 | #define _ESP8266MQTTMESH_H_ 3 | 4 | #if ! defined(MQTT_MAX_PACKET_SIZE) 5 | #define MQTT_MAX_PACKET_SIZE (1024+128+1) //1024 is the Payload size, 1 is the String Terminator and 128 should be the max topic Length 6 | #endif 7 | #if ! defined(ESP8266MESHMQTT_DISABLE_OTA) && ! defined(ESP32) 8 | //By default we support OTA 9 | #if ! defined(MQTT_MAX_PACKET_SIZE) || MQTT_MAX_PACKET_SIZE < (1024+128+1) 10 | #error "Must define MQTT_MAX_PACKET_SIZE >= (1024+128+1)" 11 | #endif 12 | #define HAS_OTA 1 13 | #else 14 | #define HAS_OTA 0 15 | #endif 16 | 17 | #include 18 | 19 | #ifdef ESP32 20 | #include 21 | #include 22 | #define USE_WIFI_ONEVENT 23 | #include "WiFiCompat.h" 24 | #else 25 | #include 26 | #include 27 | #include 28 | #endif 29 | 30 | #include 31 | #include 32 | #include 33 | //#include 34 | 35 | #ifdef ESP32 36 | #define _chipID ((uint32_t)ESP.getEfuseMac()) 37 | #else 38 | #define _chipID ESP.getChipId() 39 | #endif 40 | 41 | #define TOPIC_LEN 64 42 | 43 | #define EMMDBG_EXTRA 0x10000000 44 | #define EMMDBG_MSG 0x00000001 45 | #define EMMDBG_MSG_EXTRA (EMMDBG_EXTRA | EMMDBG_MSG) 46 | #define EMMDBG_WIFI 0x00000002 47 | #define EMMDBG_WIFI_EXTRA (EMMDBG_EXTRA | EMMDBG_WIFI) 48 | #define EMMDBG_MQTT 0x00000004 49 | #define EMMDBG_MQTT_EXTRA (EMMDBG_EXTRA | EMMDBG_MQTT) 50 | #define EMMDBG_OTA 0x00000008 51 | #define EMMDBG_OTA_EXTRA (EMMDBG_EXTRA | EMMDBG_OTA) 52 | #define EMMDBG_TIMING 0x00000010 53 | #define EMMDBG_TIMING_EXTRA (EMMDBG_EXTRA | EMMDBG_TIMING) 54 | #define EMMDBG_FS 0x00000020 55 | #define EMMDBG_FS_EXTRA (EMMDBG_EXTRA | EMMDBG_OTA) 56 | #define EMMDBG_ALL 0x8FFFFFFF 57 | #define EMMDBG_ALL_EXTRA 0xFFFFFFFF 58 | #define EMMDBG_NONE 0x00000000 59 | 60 | #ifndef ESP8266_NUM_CLIENTS 61 | #define ESP8266_NUM_CLIENTS 4 //4 seems to be them maximal Ammount the esp8266 can handle 62 | #endif 63 | 64 | enum MSG_TYPE { 65 | MSG_TYPE_NONE = 0xFE, 66 | MSG_TYPE_INVALID = 0xFF, 67 | MSG_TYPE_QOS_0 = 10, 68 | MSG_TYPE_QOS_1 = 11, 69 | MSG_TYPE_QOS_2 = 12, 70 | MSG_TYPE_RETAIN_QOS_0 = 13, 71 | MSG_TYPE_RETAIN_QOS_1 = 14, 72 | MSG_TYPE_RETAIN_QOS_2 = 15, 73 | }; 74 | 75 | #if ASYNC_TCP_SSL_ENABLED 76 | typedef struct { 77 | const uint8_t *cert; 78 | const uint8_t *key; 79 | const uint8_t *fingerprint; 80 | uint32_t cert_len; 81 | uint32_t key_len; 82 | } ssl_cert_t; 83 | #endif 84 | 85 | #if HAS_OTA 86 | typedef struct { 87 | uint32_t len; 88 | byte md5[16]; 89 | } ota_info_t; 90 | #endif 91 | 92 | typedef struct ap_t { 93 | struct ap_t *next; 94 | int32_t rssi; 95 | uint8_t bssid[6]; 96 | int16_t ssid_idx; 97 | } ap_t; 98 | 99 | typedef struct { 100 | const char *ssid; 101 | const char *password; 102 | const char *bssid; 103 | bool hidden; 104 | } wifi_conn; 105 | #define WIFI_CONN(ssid, password, bssid, hidden) \ 106 | { ssid, password, bssid, hidden } 107 | 108 | class ESP8266MQTTMesh { 109 | public: 110 | class Builder; 111 | private: 112 | const unsigned int firmware_id; 113 | const char *firmware_ver; 114 | const wifi_conn *networks; 115 | 116 | const char *mesh_ssid; 117 | char mesh_password[64]; 118 | const char *mqtt_server; 119 | const char *mqtt_username; 120 | const char *mqtt_password; 121 | const int mqtt_port; 122 | const int mesh_port; 123 | uint32_t mesh_bssid_key; 124 | 125 | const char *inTopic; 126 | const char *outTopic; 127 | 128 | char availableTopic[64]; 129 | #if HAS_OTA 130 | uint32_t freeSpaceStart; 131 | uint32_t freeSpaceEnd; 132 | uint32_t nextErase; 133 | uint32_t startTime; 134 | ota_info_t ota_info; 135 | #endif 136 | #if ASYNC_TCP_SSL_ENABLED 137 | bool mqtt_secure; 138 | ssl_cert_t mesh_secure; 139 | const uint8_t *mqtt_fingerprint; 140 | #endif 141 | AsyncServer espServer; 142 | AsyncClient *espClient[ESP8266_NUM_CLIENTS+1] = {0}; //TODO: test if this does what I hope it does! 143 | uint8_t espMAC[ESP8266_NUM_CLIENTS+1][6]; 144 | AsyncMqttClient mqttClient; 145 | 146 | Ticker schedule; 147 | 148 | bool connectScheduled = false; 149 | bool alreaddyDisconnected = false; 150 | int retry_connect; 151 | ap_t *ap = NULL; 152 | ap_t *ap_ptr = NULL; 153 | ap_t *ap_unused = NULL; 154 | char myID[10]; 155 | char inbuffer[ESP8266_NUM_CLIENTS+1][MQTT_MAX_PACKET_SIZE]; //Buffer for storing Fragmented Packages between Calls 156 | char *bufptr[ESP8266_NUM_CLIENTS+1]; //Pointer to inbuffer for handling fragmented Packages 157 | 158 | bool meshConnect = false; //If Node is connected over the Mesh or directly to the Router 159 | bool wasConnected = false; //is true if Node was connected and lost connection, false if restarted and hasn't had a connection 160 | bool p2pConnected = false; //when connected over Mesh, a peer to peer Connection gets established with the connected Node, variable shows if this Connection is ok. 161 | bool scanning = 0; //if scanning is in progress 162 | bool AP_ready = false; //if own Acess point is setup or shutdown 163 | 164 | bool blink_status = false; // if true the status_pin is blinked to show connection status 165 | unsigned long blinkInterval = 500; 166 | unsigned long lastBlink = 0; 167 | bool do_blink = false; // if true blinking is activated 168 | int status_pin = LED_BUILTIN; // pin used to signal connection status 169 | 170 | std::function callback; //TODO: check out this syntax 171 | 172 | bool wifiConnected() { return (WiFi.status() == WL_CONNECTED); } 173 | void die() { ESP.restart(); while(1) {} } 174 | 175 | uint32_t lfsr(uint32_t seed, uint8_t b); 176 | uint32_t encrypt_id(uint32_t id); 177 | void generate_mac(uint8_t *bssid, uint32_t id); 178 | bool verify_bssid(uint8_t *bssid); 179 | 180 | int match_networks(const char *ssid, const char *bssid); 181 | void scan(); 182 | void connect(); 183 | static void connect_static(ESP8266MQTTMesh *e) { e->connect(); }; 184 | String mac_str(uint8_t *bssid); 185 | const char *build_mesh_ssid(char buf[32], uint8_t *mac); 186 | void schedule_connect(float delay = 5.0); 187 | void connect_mqtt(); 188 | void shutdown_AP(); 189 | void setup_AP(); 190 | void handle_client_data(int idx, char *data); 191 | void HandleMessages(const char *topic, const char *msg); 192 | void parse_message(const char *topic, const char *msg); 193 | void mqtt_callback(const char* topic, const byte* payload, unsigned int length); 194 | uint16_t mqtt_publish(const char *topic, const char *msg, uint8_t msgType); 195 | void publish(const char *topicDirection, const char *baseTopic, const char *subTopic, const char *msg, uint8_t msgType); 196 | bool send_message(int index, const char *topicOrMsg, const char *msg = NULL, uint8_t msgType = MSG_TYPE_NONE); 197 | void send_messages(); 198 | void send_connected_msg(); 199 | void broadcast_message(const char *topicOrMsg, const char *msg = NULL); 200 | void get_fw_string(char *msg, int len, const char *prefix); 201 | void handle_fw(const char *cmd); 202 | void handle_ota(const char *cmd, const char *msg); 203 | void parse_ota_info(const char *str); 204 | char * md5(const uint8_t *msg, int len); 205 | bool check_ota_md5(); 206 | void assign_subdomain(); 207 | static void checkConnectionEstablished(ESP8266MQTTMesh *e); 208 | 209 | void checkConnectionEstablished(); 210 | static void checkConnectionEstablished_static(ESP8266MQTTMesh *e) { e->checkConnectionEstablished(); }; 211 | 212 | static void assign_subdomain(ESP8266MQTTMesh *e) { e->assign_subdomain(); }; 213 | void erase_sector(); 214 | static void erase_sector(ESP8266MQTTMesh *e) { e->erase_sector(); }; 215 | 216 | void connectWiFiEvents(); 217 | 218 | #ifndef USE_WIFI_ONEVENT 219 | WiFiEventHandler wifiConnectHandler; 220 | WiFiEventHandler wifiDisconnectHandler; 221 | WiFiEventHandler wifiAPConnectHandler; 222 | WiFiEventHandler wifiAPDisconnectHandler; 223 | #endif 224 | 225 | void onWifiConnect(const WiFiEventStationModeGotIP& event); 226 | void onWifiDisconnect(const WiFiEventStationModeDisconnected& event); 227 | //void onDHCPTimeout(); 228 | void onAPConnect(const WiFiEventSoftAPModeStationConnected& ip); 229 | void onAPDisconnect(const WiFiEventSoftAPModeStationDisconnected& ip); 230 | 231 | void onMqttConnect(bool sessionPresent); 232 | void onMqttDisconnect(AsyncMqttClientDisconnectReason reason); 233 | void onMqttSubscribe(uint16_t packetId, uint8_t qos); 234 | void onMqttUnsubscribe(uint16_t packetId); 235 | void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total); 236 | void onMqttPublish(uint16_t packetId); 237 | 238 | int onSslFileRequest(const char *filename, uint8_t **buf); 239 | void onClient(AsyncClient* c); 240 | void onConnect(AsyncClient* c); 241 | void onDisconnect(AsyncClient* c); 242 | void onError(AsyncClient* c, int8_t error); 243 | void onAck(AsyncClient* c, size_t len, uint32_t time); 244 | void onTimeout(AsyncClient* c, uint32_t time); 245 | void onData(AsyncClient* c, void* data, size_t len); 246 | 247 | ESP8266MQTTMesh(const wifi_conn *networks, 248 | const char *mqtt_server, int mqtt_port, 249 | const char *mqtt_username, const char *mqtt_password, 250 | const char *firmware_ver, int firmware_id, 251 | const char *mesh_ssid, const char *mesh_password, int mesh_port, 252 | #if ASYNC_TCP_SSL_ENABLED 253 | bool mqtt_secure, const uint8_t *mqtt_fingerprint, ssl_cert_t mesh_secure, 254 | #endif 255 | const char *inTopic, const char *outTopic); 256 | public: 257 | void setCallback(std::function _callback); 258 | void setType(uint32_t type); 259 | void begin(); 260 | void publish(const char *subtopic, const char *msg, enum MSG_TYPE msgCmd = MSG_TYPE_NONE); 261 | void publish_node(const char *subtopic, const char *msg, enum MSG_TYPE msgCmd = MSG_TYPE_NONE); 262 | bool connected(); 263 | static bool keyValue(const char *data, char separator, char *key, int keylen, const char **value); 264 | #ifdef USE_WIFI_ONEVENT 265 | #ifdef ESP32 266 | void WiFiEventHandler(arduino_event_id_t event, arduino_event_info_t info); 267 | #else 268 | void WiFiEventHandler(system_event_id_t event, system_event_info_t info); 269 | #endif 270 | #endif 271 | void setID(const char *id); 272 | 273 | void loop(); // function to be run in the main loop 274 | void set_blink_status(bool value) {blink_status = value;} 275 | void set_status_pin(int value) {status_pin = value;} 276 | }; 277 | 278 | #include "ESP8266MQTTMeshBuilder.h" 279 | 280 | #endif //_ESP8266MQTTMESH_H_ 281 | -------------------------------------------------------------------------------- /src/ESP8266MQTTMeshBuilder.h: -------------------------------------------------------------------------------- 1 | #ifndef _ESP8266MQTTMESHBUILDER_H_ 2 | #define _ESP8266MQTTMESHBUILDER_H_ 3 | 4 | class ESP8266MQTTMesh::Builder { 5 | private: 6 | const wifi_conn *networks; 7 | 8 | const char *mqtt_server; 9 | int mqtt_port; 10 | const char *mqtt_username; 11 | const char *mqtt_password; 12 | 13 | const char *mesh_ssid; 14 | const char *mesh_password; 15 | int mesh_port; 16 | 17 | unsigned int firmware_id; 18 | const char *firmware_ver; 19 | #if ASYNC_TCP_SSL_ENABLED 20 | bool mqtt_secure; 21 | ssl_cert_t mesh_secure; 22 | const uint8_t *mqtt_fingerprint; 23 | void fix_mqtt_port() { if (! mqtt_port) mqtt_port = mqtt_secure ? 8883 : 1883; }; 24 | #else 25 | void fix_mqtt_port() { if (! mqtt_port) mqtt_port = 1883; }; 26 | #endif 27 | 28 | const char* inTopic; 29 | const char* outTopic; 30 | 31 | public: 32 | Builder(const wifi_conn *networks, 33 | const char *mqtt_server, 34 | int mqtt_port = 0): 35 | networks(networks), 36 | mqtt_server(mqtt_server), 37 | mqtt_port(mqtt_port), 38 | mqtt_username(NULL), 39 | mqtt_password(NULL), 40 | mesh_ssid("esp8266_mqtt_mesh"), 41 | mesh_password("ESP8266MQTTMesh"), 42 | mesh_port(1884), 43 | firmware_id(0), 44 | firmware_ver(NULL), 45 | #if ASYNC_TCP_SSL_ENABLED 46 | mqtt_secure(false), 47 | mqtt_fingerprint(NULL), 48 | mesh_secure({NULL, NULL, NULL, 0, 0}), 49 | #endif 50 | inTopic("esp8266-in/"), 51 | outTopic("esp8266-out/") 52 | 53 | {} 54 | Builder& setVersion(const char *firmware_ver, int firmware_id) { 55 | this->firmware_id = firmware_id; 56 | this->firmware_ver = firmware_ver; 57 | return *this; 58 | } 59 | Builder& setMqttAuth(const char *username, const char *password) { 60 | this->mqtt_username = username; 61 | this->mqtt_password = password; 62 | return *this; 63 | } 64 | Builder& setMeshSSID(const char *ssid) { this->mesh_ssid = ssid; return *this; } 65 | Builder& setMeshPassword(const char *password) { this->mesh_password = password; return *this; } 66 | Builder& setMeshPort(int port) { this->mesh_port = port; return *this; } 67 | Builder& setTopic(const char *inTopic, const char *outTopic) { 68 | this->inTopic = inTopic; 69 | this->outTopic = outTopic; 70 | return *this; 71 | } 72 | #if ASYNC_TCP_SSL_ENABLED 73 | Builder& setMqttSSL(bool enable, const uint8_t *fingerprint) { 74 | this->mqtt_secure = enable; 75 | this->mqtt_fingerprint = fingerprint; 76 | return *this; 77 | } 78 | Builder & setMeshSSL(const uint8_t *ssl_cert, uint32_t ssl_cert_len, 79 | const uint8_t *ssl_key, uint32_t ssl_key_len, 80 | const uint8_t *ssl_fingerprint) { 81 | this->mesh_secure.cert = ssl_cert; 82 | this->mesh_secure.key = ssl_key; 83 | this->mesh_secure.fingerprint = ssl_fingerprint; 84 | this->mesh_secure.cert_len = ssl_cert_len; 85 | this->mesh_secure.key_len = ssl_key_len; 86 | return *this; 87 | } 88 | #endif 89 | ESP8266MQTTMesh build() { 90 | fix_mqtt_port(); 91 | return( ESP8266MQTTMesh( 92 | networks, 93 | 94 | mqtt_server, 95 | mqtt_port, 96 | mqtt_username, 97 | mqtt_password, 98 | 99 | firmware_ver, 100 | firmware_id, 101 | 102 | mesh_ssid, 103 | mesh_password, 104 | mesh_port, 105 | 106 | #if ASYNC_TCP_SSL_ENABLED 107 | mqtt_secure, 108 | mqtt_fingerprint, 109 | mesh_secure, 110 | #endif 111 | 112 | inTopic, 113 | outTopic)); 114 | } 115 | ESP8266MQTTMesh *buildptr() { 116 | fix_mqtt_port(); 117 | return( new ESP8266MQTTMesh( 118 | networks, 119 | 120 | mqtt_server, 121 | mqtt_port, 122 | mqtt_username, 123 | mqtt_password, 124 | 125 | firmware_ver, 126 | firmware_id, 127 | 128 | mesh_ssid, 129 | mesh_password, 130 | mesh_port, 131 | 132 | #if ASYNC_TCP_SSL_ENABLED 133 | mqtt_secure, 134 | mqtt_fingerprint, 135 | mesh_secure, 136 | #endif 137 | 138 | inTopic, 139 | outTopic)); 140 | } 141 | }; 142 | #endif //_ESP8266MQTTMESHBUILDER_H_ 143 | -------------------------------------------------------------------------------- /src/WiFiCompat.h: -------------------------------------------------------------------------------- 1 | /* This header file defines compatible structs that are not present in ESP32 */ 2 | #ifndef _WIFI_COMPAT_ 3 | #define _WIFI_COMPAT_ 4 | 5 | #include 6 | #include "esp_mac.h" 7 | 8 | typedef enum { 9 | STATION_IF = 0, /**< ESP32 station interface */ 10 | SOFTAP_IF, /**< ESP32 soft-AP interface */ 11 | MAX_IF 12 | } WIFI_INTERFACE; 13 | 14 | static bool wifi_set_macaddr(WIFI_INTERFACE if_index, uint8_t *macaddr) { 15 | if (if_index == SOFTAP_IF) { 16 | int ok = esp_base_mac_addr_set(macaddr); 17 | return ok == ESP_OK; 18 | } 19 | return true; 20 | } 21 | 22 | #define WIFI_DISCONNECT_REASON_ASSOC_TOOMANY WIFI_REASON_ASSOC_TOOMANY 23 | struct WiFiEventStationModeGotIP 24 | { 25 | IPAddress ip; 26 | IPAddress mask; 27 | IPAddress gw; 28 | }; 29 | 30 | struct WiFiEventStationModeDisconnected 31 | { 32 | String ssid; 33 | uint8_t bssid[6]; 34 | unsigned int reason; 35 | }; 36 | 37 | /* 38 | struct WiFiEventSoftAPModeStationConnected 39 | { 40 | uint8_t mac[6]; 41 | uint8_t aid; 42 | }; 43 | */ 44 | #define WiFiEventSoftAPModeStationConnected wifi_event_ap_staconnected_t 45 | /* 46 | struct WiFiEventSoftAPModeStationDisconnected 47 | { 48 | uint8_t mac[6]; 49 | uint8_t aid; 50 | }; 51 | */ 52 | #define WiFiEventSoftAPModeStationDisconnected wifi_event_ap_stadisconnected_t 53 | 54 | #endif //_WIFI_COMPAT_ 55 | 56 | -------------------------------------------------------------------------------- /utils/dump_stacktrace.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import subprocess 3 | import sys 4 | import re 5 | import os 6 | 7 | firmware = sys.argv[1] 8 | stacktrace = sys.argv[2] 9 | objdump = os.environ['HOME'] + "/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-objdump" 10 | 11 | dump = subprocess.check_output([objdump, '-S',firmware]).split('\n') 12 | funcs = [] 13 | start = None 14 | end = None 15 | for line in dump: 16 | #40208544 <_ZN15ESP8266MQTTMesh8setup_APEv>: 17 | match = re.match(r'([0-9a-f]{8})\s+<(.*)>:', line) 18 | if match: 19 | funcs.append([int(match.group(1), 16), match.group(2)]) 20 | match = re.match(r'([0-9a-f]{8}):',line) 21 | if match: 22 | add = int(match.group(1), 16) 23 | if not end or add > end: 24 | end = add 25 | if not start or add < start: 26 | start = add 27 | with open(stacktrace, "r") as fh: 28 | in_stack = False 29 | for line in fh: 30 | if re.search(r'>>>stack>>>', line): 31 | in_stack = True 32 | if in_stack: 33 | addrs = re.split(r'[: ]+', line) 34 | for addr in addrs: 35 | try: 36 | add = int(addr, 16) 37 | except: 38 | continue 39 | if add < start or add > end: 40 | #print("Ignoring: %s (%08x, %08x)" % (addr, start, end)) 41 | continue 42 | for i in range(0, len(funcs)): 43 | if funcs[i][0] <= add: 44 | continue 45 | print("%s : %s" % (addr, funcs[i-1][1])) 46 | break 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /utils/gen_server_cert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #This script is a slightly modified copy of: 3 | #https://github.com/me-no-dev/ESPAsyncTCP/blob/master/ssl/gen_server_cert.sh 4 | cat > ca_cert.conf << EOF 5 | [ req ] 6 | distinguished_name = req_distinguished_name 7 | prompt = no 8 | 9 | [ req_distinguished_name ] 10 | O = Espressif Systems 11 | EOF 12 | 13 | openssl genrsa -out axTLS.ca_key.pem 2048 14 | openssl req -new -config ./ca_cert.conf -key axTLS.ca_key.pem -out axTLS.ca_x509.req 15 | openssl x509 -req -sha1 -days 5000 -signkey axTLS.ca_key.pem -CAkey axTLS.ca_key.pem -in axTLS.ca_x509.req -out axTLS.ca_x509.pem 16 | 17 | cat > certs.conf << EOF 18 | [ req ] 19 | distinguished_name = req_distinguished_name 20 | prompt = no 21 | 22 | [ req_distinguished_name ] 23 | O = axTLS on ESP8266 24 | CN = esp8266.local 25 | EOF 26 | 27 | openssl genrsa -out axTLS.key_1024.pem 1024 28 | openssl req -new -config ./certs.conf -key axTLS.key_1024.pem -out axTLS.x509_1024.req 29 | openssl x509 -req -sha1 -CAcreateserial -days 5000 -CA axTLS.ca_x509.pem -CAkey axTLS.ca_key.pem -in axTLS.x509_1024.req -out axTLS.x509_1024.pem 30 | 31 | openssl rsa -outform DER -in axTLS.key_1024.pem -out axTLS.key_1024 32 | openssl x509 -outform DER -in axTLS.x509_1024.pem -out axTLS.x509_1024.cer 33 | 34 | cat axTLS.key_1024 > server.key 35 | cat axTLS.x509_1024.cer > server.cer 36 | python -c 'import os; import hashlib; os.write(1,hashlib.sha1(open("server.cer", "rb").read()).digest())' > fingerprint 37 | 38 | echo "const uint8_t ssl_key[] =" > ssl_cert.h 39 | hexdump -v -e '16/1 "_x%02X" "\n"' server.key | sed 's/_/\\/g; s/\\x //g; s/.*/ "&"/' >> ssl_cert.h 40 | echo ";" >> ssl_cert.h 41 | echo "const uint32_t ssl_key_len = `cat server.key | wc -c`;" >> ssl_cert.h 42 | 43 | echo "const uint8_t ssl_cert[] =" >> ssl_cert.h 44 | hexdump -v -e '16/1 "_x%02X" "\n"' server.cer | sed 's/_/\\/g; s/\\x //g; s/.*/ "&"/' >> ssl_cert.h 45 | echo ";" >> ssl_cert.h 46 | echo "const uint32_t ssl_cert_len = `cat server.cer | wc -c`;" >> ssl_cert.h 47 | 48 | echo "const uint8_t ssl_fingerprint[] =" >> ssl_cert.h 49 | hexdump -v -e '16/1 "_x%02X" "\n"' fingerprint | sed 's/_/\\/g; s/\\x //g; s/.*/ "&"/' >> ssl_cert.h 50 | echo ";" >> ssl_cert.h 51 | 52 | rm axTLS.* ca_cert.conf certs.conf 53 | -------------------------------------------------------------------------------- /utils/get_mqtt_fingerprint.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This script originally came from: 4 | # https://github.com/marvinroger/async-mqtt-client/blob/master/scripts/get-fingerprint/get-fingerprint.py 5 | 6 | import argparse 7 | import ssl 8 | import hashlib 9 | import binascii 10 | import sys 11 | import socket 12 | 13 | # The following came from https://tools.ietf.org/html/rfc5754#section-3 14 | # This is crude, but works without requireing additional dependencies 15 | 16 | signatures = { 17 | "dsa_sha224": "30 0b 06 09 60 86 48 01 65 03 04 03 01", 18 | "dsa_sha256": "30 0b 06 09 60 86 48 01 65 03 04 03 02", 19 | "rsa_sha224": "30 0d 06 09 2a 86 48 86 f7 0d 01 01 0e 05 00", 20 | "rsa_sha256": "30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00", 21 | "rsa_sha384": "30 0d 06 09 2a 86 48 86 f7 0d 01 01 0c 05 00", 22 | "rsa_sha512": "30 0d 06 09 2a 86 48 86 f7 0d 01 01 0d 05 00", 23 | "ecdsa_sha224": "30 0a 06 08 2a 86 48 ce 3d 04 03 01", 24 | "ecdsa_sha256": "30 0a 06 08 2a 86 48 ce 3d 04 03 02", 25 | "ecdsa_sha384": "30 0a 06 08 2a 86 48 ce 3d 04 03 03", 26 | "ecdsa_sha512": "30 0a 06 08 2a 86 48 ce 3d 04 03 04" 27 | } 28 | 29 | parser = argparse.ArgumentParser(description='Compute SSL/TLS fingerprints.') 30 | parser.add_argument('--host', required=True) 31 | parser.add_argument('--port', default=8883) 32 | 33 | args = parser.parse_args() 34 | 35 | try: 36 | cert_pem = ssl.get_server_certificate((args.host, args.port)) 37 | cert_der = ssl.PEM_cert_to_DER_cert(cert_pem) 38 | except socket.error as e: 39 | if str(e).find("[Errno 111]") is not -1: 40 | print("ERROR: Could not connect to %s:%s" % (args.host, args.port)) 41 | elif str(e).find("[Errno 104]") is not -1: 42 | print("ERROR: Mosquitto broker does not appear to be using TLS at %s:%s" % (args.host, args.port)) 43 | print(e) 44 | sys.exit(1) 45 | 46 | matches = [] 47 | for k in signatures: 48 | fingerprint = binascii.a2b_hex(signatures[k].replace(" ", "")) 49 | if cert_der.find(fingerprint) is not -1: 50 | matches.append(k) 51 | if not matches: 52 | print("WARNING: Couldn't identify signature algorithm") 53 | else: 54 | print("INFO: Found signature algorithm: " + ", ".join(matches)) 55 | for sig in ("rsa_sha384", "rsa_sha512", "ecdsa_sha384", "ecdsa_sha512"): 56 | if sig in matches: 57 | print("ERROR: MQTT broker is using a %s signature which will not work with ESP8266" % (sig)) 58 | 59 | sha1 = hashlib.sha1(cert_der).hexdigest() 60 | 61 | print("const uint8_t MQTT_FINGERPRINT[] = {0x" + ",0x".join([sha1[i:i+2] for i in range(0, len(sha1), 2)]) + "};") 62 | -------------------------------------------------------------------------------- /utils/send_ota.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import paho.mqtt.client as mqtt 4 | import os 5 | import sys 6 | import argparse 7 | import hashlib 8 | import base64 9 | import time 10 | import ssl 11 | import re 12 | import queue 13 | 14 | 15 | topic = "esp8266-" 16 | inTopic = topic + "in" 17 | outTopic = topic + "out" 18 | send_topic = "" 19 | name = "" 20 | passw = "" 21 | q = queue.Queue() 22 | maxMQTTMessageLength = 768 23 | 24 | 25 | def regex(pattern, txt, group): 26 | group.clear() 27 | match = re.search(pattern, txt) 28 | if match: 29 | if match.groupdict(): 30 | for k,v in match.groupdict().items(): 31 | group[k] = v 32 | else: 33 | group.extend(match.groups()) 34 | return True 35 | return False 36 | 37 | 38 | def on_connect(client, userdata, flags, rc): 39 | print("Connected with result code "+str(rc)) 40 | 41 | # Subscribing in on_connect() means that if we lose the connection and 42 | # reconnect then subscriptions will be renewed. 43 | client.subscribe("{}/#".format(outTopic)) 44 | 45 | 46 | # The callback for when a PUBLISH message is received from the server. 47 | def on_message(client, userdata, msg): 48 | #esp8266-out/mesh_esp8266-6/check=MD5 Passed 49 | match = [] 50 | if regex(r'/([0-9a-fA-F]+)/ota/erase$', msg.topic, match): 51 | q.put(["erase", match[0]]) 52 | elif regex(r'([0-9a-fA-F]+)/ota/md5/([0-9a-fA-F]+)', msg.topic, match): 53 | q.put(["md5", match[0], match[1], msg.payload]) 54 | elif regex(r'([0-9a-fA-F]+)/ota/check$', msg.topic, match): 55 | q.put(["check", match[0], msg.payload]) 56 | else: 57 | #print("%s %-30s = %s" % (str(datetime.datetime.now()), msg.topic, str(msg.payload))); 58 | pass 59 | 60 | 61 | def wait_for(nodes, msgtype, maxTime): 62 | seen = {} 63 | origTime = time.time() 64 | startTime = origTime 65 | while True: 66 | try: 67 | msg = q.get(True, 0.1) 68 | if msg[0] == msgtype and (not nodes or msg[1] in nodes): 69 | node = msg[1] 70 | seen[node] = msg 71 | else: 72 | print("Got unexpected {} for node {}".format(msgtype, msg[1], msg)) 73 | except queue.Empty: 74 | if time.time() - startTime < maxTime: 75 | continue 76 | if nodes: 77 | print("{} node(s) missed the message".format(len(nodes) - len(seen.keys()))) 78 | break 79 | if nodes and len(seen.keys()) == len(nodes): #if the Nodes are getting updated by their Module ID 80 | break 81 | #print("Elapsed time waiting for {} messages: {} seconds".format(msgtype, time.time() - origTime)) 82 | return seen 83 | 84 | 85 | def send_firmware(client, data, nodes): 86 | md5 = base64.b64encode(hashlib.md5(data).digest()) 87 | payload = "md5:%s,len:%d" %(md5.decode(), len(data)) 88 | print("Erasing...") 89 | client.publish("{}start".format(send_topic), payload) 90 | nodes = list(wait_for(nodes, 'erase', 10).keys()) 91 | if not nodes: 92 | print("No nodes responded to erase. Aborting") 93 | sys.exit(1) 94 | print("Updating firmware on the following nodes:\n\t{}".format("\n\t".join(nodes))) 95 | pos = 0 96 | while len(data): 97 | d = data[0:maxMQTTMessageLength] 98 | b64d = base64.b64encode(d) 99 | data = data[maxMQTTMessageLength:] 100 | topic = "{}{}".format(send_topic, str(pos)) 101 | client.publish(topic, b64d) 102 | expected_md5 = hashlib.md5(d).hexdigest().encode('utf-8') 103 | retries = 0 104 | seen = {} 105 | while True: 106 | seen.update(wait_for(nodes, 'md5', 30.0)) 107 | if len(seen.keys()) == len(nodes): 108 | break 109 | 110 | if retries == 0: 111 | break 112 | 113 | client.publish(topic, b64d) 114 | retries -= 1 115 | 116 | for node in nodes: 117 | if node not in seen: 118 | print("No MD5 found for {} at 0x{} (expected {})".format(node, pos, expected_md5)) 119 | return 120 | addr = int(seen[node][2], 16) 121 | md5 = seen[node][3] 122 | if pos != addr: 123 | raise RuntimeError("Got unexpected address 0x{} (expected: 0x{}) from node {}".format(addr, pos, node)) 124 | 125 | if md5 != expected_md5: 126 | print("Got unexpected md5 for node {} at 0x{},\n" 127 | "maybe the send Packages are to large for your MCU, if this happens every time try using the Argument: --packageLength".format(node, addr)) 128 | print("\t {} (expected: {})".format(md5, expected_md5)) 129 | return 130 | 131 | pos += len(d) 132 | if pos % (int(10000/maxMQTTMessageLength)*maxMQTTMessageLength) == 0: #aproximately every 10kb of send Data 133 | print("Transmitted %d bytes" % pos) 134 | print("Completed send") 135 | client.publish("{}check".format(send_topic), "") 136 | seen = wait_for(nodes, 'check', 5) 137 | err = False 138 | for node in nodes: 139 | if node not in seen: 140 | print("No verify result found for {}".format(node)) 141 | err = True 142 | if seen[node][2] != b'MD5 Passed': 143 | print("Node {} did not pass final MD5 check: {},\n" 144 | "maybe the send Packages are to large for your MCU, if this happens every time try using the Argument: --packageLength".format(node, seen[node][2])) 145 | err = True 146 | if err: 147 | return 148 | print("Checksum verified. Flashing and rebooting now...") 149 | client.publish("{}flash".format(send_topic), "") 150 | 151 | def main(): 152 | global inTopic, outTopic, name, passw, send_topic, maxMQTTMessageLength 153 | parser = argparse.ArgumentParser() 154 | parser.add_argument("--bin", help="Input file"); 155 | parser.add_argument("--id", help="Firmware ID (n HEX)"); 156 | parser.add_argument("--broker", help="MQTT broker"); 157 | parser.add_argument("--port", help="MQTT broker port"); 158 | parser.add_argument("--user", help="MQTT broker user"); 159 | parser.add_argument("--password", help="MQTT broker password"); 160 | parser.add_argument("--ssl", help="MQTT broker SSL support"); 161 | parser.add_argument("--topic", help="MQTT mesh topic base (default: {})".format(topic)) 162 | parser.add_argument("--intopic", help="MQTT mesh in-topic (default: {})".format(inTopic)) 163 | parser.add_argument("--outtopic", help="MQTT mesh out-topic (default: {})".format(outTopic)) 164 | parser.add_argument("--node", help="Specific node to send firmware to") 165 | parser.add_argument("--packageLength", help="Max ESP Payload Length, lower when always MD5 Mismatch (default: {})".format(outTopic)) 166 | args = parser.parse_args() 167 | 168 | if args.packageLength: 169 | maxMQTTMessageLength = int(args.packageLength) 170 | 171 | if not os.path.isfile(args.bin): 172 | print("File: " + args.bin + " does not exist") 173 | sys.exit(1) 174 | 175 | if args.topic: 176 | inTopic = args.topic + "in" 177 | outTopic = args.topic + "out" 178 | if args.intopic: 179 | inTopic = args.intopic 180 | if args.outtopic: 181 | outTopic = args.outtopic 182 | 183 | if args.id: 184 | send_topic = "{}/ota/{}/".format(inTopic, args.id) 185 | elif args.node: 186 | send_topic = "{}/ota/{}/".format(inTopic, args.node) 187 | else: 188 | print("Must specify either --id or --node") 189 | sys.exit(1) 190 | print("File: {}".format(args.bin)) 191 | print("Sending to topic: {}".format(send_topic)) 192 | print("Listening to topic: {}".format(outTopic)) 193 | 194 | if not args.broker: 195 | args.broker = "127.0.0.1" 196 | if not args.port: 197 | args.port = 1883 198 | 199 | if args.user: 200 | name = args.user 201 | if args.password: 202 | passw = args.password 203 | 204 | client = mqtt.Client() 205 | if args.ssl: 206 | client.tls_set(ca_certs=None, certfile=None, keyfile=None, cert_reqs=ssl.CERT_REQUIRED,tls_version=ssl.PROTOCOL_TLS, ciphers=None) 207 | if (args.user) or (args.password): 208 | client.username_pw_set(name,passw) 209 | client.on_connect = on_connect 210 | client.on_message = on_message 211 | 212 | client.connect(args.broker, int(args.port), 60) 213 | client.loop_start() 214 | 215 | fh = open(args.bin, "rb") 216 | data = fh.read() 217 | fh.close() 218 | 219 | send_firmware(client, data, [args.node] if args.node else []) 220 | 221 | client.loop_stop() 222 | client.disconnect() 223 | 224 | 225 | main() 226 | --------------------------------------------------------------------------------