Advertisement
Guest User

swz15

a guest
Feb 6th, 2017
52
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.37 KB | None | 0 0
  1. /*
  2. Configuration for Home Assistant:
  3. mqtt:
  4. broker: 127.0.0.1
  5. port: 1883
  6. client_id: 'ha'
  7. username: 'ha'
  8. password: '!ha@OpenHome16'
  9.  
  10. light:
  11. - platform: mqtt
  12. name: 'Lamp 1'
  13. state_topic: 'entrance/light1/status'
  14. command_topic: 'entrance/light1/switch'
  15. optimistic: false
  16. - platform: mqtt
  17. name: 'Lamp 2'
  18. state_topic: 'entrance/light2/status'
  19. command_topic: 'entrance/light2/switch'
  20. optimistic: false
  21.  
  22. binary_sensor:
  23. - platform: mqtt
  24. name: 'Motion'
  25. state_topic: 'entrance/door/motion/status'
  26. sensor_class: motion
  27.  
  28. Sources:
  29. - MQTT: File > Examples > PubSubClient > mqtt_esp8266
  30. - TLS: https://io.adafruit.com/blog/security/2016/07/05/adafruit-io-security-esp8266/
  31. - OTA: File > Examples > ArduinoOTA > BasicOTA
  32. - PIR: https://learn.adafruit.com/pir-passive-infrared-proximity-motion-sensor/using-a-pir
  33. */
  34.  
  35. #include <ESP8266WiFi.h> // https://github.com/esp8266/Arduino (GNUv2.1 licence)
  36. #include <PubSubClient.h> // https://github.com/knolleary/pubsubclient (no licence)
  37. #include <ArduinoOTA.h>
  38.  
  39. //#define DEBUG
  40. #define TLS
  41. #define MQTT_VERSION MQTT_VERSION_3_1_1
  42.  
  43. // Wi-Fi: Access Point SSID and password
  44. const char* AP_SSID = "FineNetU";
  45. const char* AP_PASSWORD = "taoandalison";
  46.  
  47. // MQTT: client ID, broker IP address, port, username & password
  48. const char* MQTT_CLIENT_ID = "entrance";
  49. const char* MQTT_SERVER_IP = "10.0.0.17";
  50. #ifdef TLS
  51. const uint16_t MQTT_SERVER_PORT = 8883;
  52. #else
  53. const uint16_t MQTT_SERVER_PORT = 1883;
  54. #endif
  55. //const char* MQTT_USERNAME = "entrance";
  56. //const char* MQTT_PASSWORD = "[Redacted]";
  57.  
  58. // MQTT: topics
  59. // lamp 1
  60. const char* TOPIC_LIGHT1_STATUS = "entrance/light1/status";
  61. const char* TOPIC_LIGHT1_COMMAND = "entrance/light1/switch";
  62. // lamp 2
  63. const char* TOPIC_LIGHT2_STATUS = "entrance/light2/status";
  64. const char* TOPIC_LIGHT2_COMMAND = "entrance/light2/switch";
  65. // motion sensor
  66. const char* TOPIC_MOTION_STATUS = "entrance/door/motion/status";
  67.  
  68. // MQTT: payloads
  69. // Lamps 1 & 2 + motion sensor: "ON"/"OFF"
  70. const char* PAYLOAD_ON = "ON";
  71. const char* PAYLOAD_OFF = "OFF";
  72.  
  73. boolean g_light1_status = false; // turn off by default
  74. boolean g_light2_status = false;
  75. volatile boolean g_motion_status = false; // no motion by default
  76. volatile boolean g_motion_change = false; // no publication to do by default
  77.  
  78.  
  79. const uint8_t LIGHT1_PIN = D1;
  80. const uint8_t LIGHT2_PIN = D2;
  81. const uint8_t MOTION_SENSOR_PIN = D8; // connected before to D3, strange behaviour when D1/D2 was HIGH
  82.  
  83. // TLS: The fingerprint of the MQTT broker certificate (SHA1)
  84. #ifdef TLS
  85. // openssl x509 -fingerprint -in <certificate>.crt
  86. const char* CA_FINGERPRINT = "[Redacted]";
  87. // openssl x509 -subject -in <certificate>.crt
  88. const char* CA_SUBJECT = "[Redacted]";
  89. #endif
  90.  
  91. // Fixed IP address: IP address, IP gateway, subnet, dns
  92. const IPAddress IP (10, 0, 0, 19);
  93. const IPAddress IP_GATEWAY (10, 0, 0, 1);
  94. const IPAddress IP_SUBNET (255, 255, 255, 0);
  95. const IPAddress IP_DNS (10, 0, 0, 1);
  96.  
  97. // OTA: Hostname (MQTT_CLIENT_ID) & password
  98. const char* OTA_PASSWORD = "[Redacted]";
  99.  
  100. // WiFiFlientSecure instead of WiFiClient, for SSL/TLS support
  101. #ifdef TLS
  102. WiFiClientSecure g_wifiClient;
  103. #else
  104. WiFiClient g_wifiClient;
  105. #endif
  106. PubSubClient g_mqttClient(g_wifiClient);
  107.  
  108. ///////////////////////////////////////////////////////////////////////////
  109. //
  110. // LIGHT 1
  111. //
  112. ///////////////////////////////////////////////////////////////////////////
  113.  
  114. /*
  115. Function called to publish the status of the light 1
  116. */
  117. void publishLight1Status() {
  118. if (g_light1_status) {
  119. if (g_mqttClient.publish(TOPIC_LIGHT1_STATUS, PAYLOAD_ON, true)) {
  120. #ifdef DEBUG
  121. Serial.print(F("INFO: MQTT message publish succeeded. Topic: "));
  122. Serial.print(TOPIC_LIGHT1_STATUS);
  123. Serial.print(F(". Payload: "));
  124. Serial.println(PAYLOAD_ON);
  125. #endif
  126. } else {
  127. #ifdef DEBUG
  128. Serial.println(F("ERROR: MQTT message publish failed, either connection lost, or message too large"));
  129. #endif
  130. }
  131. } else {
  132. if (g_mqttClient.publish(TOPIC_LIGHT1_STATUS, PAYLOAD_OFF, true)) {
  133. #ifdef DEBUG
  134. Serial.print(F("INFO: MQTT message publish succeeded. Topic: "));
  135. Serial.print(TOPIC_LIGHT1_STATUS);
  136. Serial.print(F(". Payload: "));
  137. Serial.println(PAYLOAD_OFF);
  138. #endif
  139. } else {
  140. #ifdef DEBUG
  141. Serial.println(F("ERROR: MQTT message publish failed, either connection lost, or message too large"));
  142. #endif
  143. }
  144. }
  145. }
  146.  
  147. /*
  148. Function called to switch the status of the light 1
  149. */
  150. void setLight1Status() {
  151. if (g_light1_status) {
  152. digitalWrite(LIGHT1_PIN, HIGH);
  153. } else {
  154. digitalWrite(LIGHT1_PIN, LOW);
  155. }
  156. }
  157.  
  158. ///////////////////////////////////////////////////////////////////////////
  159. //
  160. // LIGHT 2
  161. //
  162. ///////////////////////////////////////////////////////////////////////////
  163.  
  164. /*
  165. Function called to publish the status of the light 2
  166. */
  167. void publishLight2Status() {
  168. if (g_light2_status) {
  169. if (g_mqttClient.publish(TOPIC_LIGHT2_STATUS, PAYLOAD_ON, true)) {
  170. #ifdef DEBUG
  171. Serial.print(F("INFO: MQTT message publish succeeded. Topic: "));
  172. Serial.print(TOPIC_LIGHT2_STATUS);
  173. Serial.print(F(". Payload: "));
  174. Serial.println(PAYLOAD_ON);
  175. #endif
  176. } else {
  177. #ifdef DEBUG
  178. Serial.println(F("ERROR: MQTT message publish failed, either connection lost, or message too large"));
  179. #endif
  180. }
  181. } else {
  182. if (g_mqttClient.publish(TOPIC_LIGHT2_STATUS, PAYLOAD_OFF, true)) {
  183. #ifdef DEBUG
  184. Serial.print(F("INFO: MQTT message publish succeeded. Topic: "));
  185. Serial.print(TOPIC_LIGHT2_STATUS);
  186. Serial.print(F(". Payload: "));
  187. Serial.println(PAYLOAD_OFF);
  188. #endif
  189. } else {
  190. #ifdef DEBUG
  191. Serial.println(F("ERROR: MQTT message publish failed, either connection lost, or message too large"));
  192. #endif
  193. }
  194. }
  195. }
  196.  
  197. /*
  198. Function called to switch the status of the light 2
  199. */
  200. void setLight2Status() {
  201. if (g_light2_status) {
  202. digitalWrite(LIGHT2_PIN, HIGH);
  203. } else {
  204. digitalWrite(LIGHT2_PIN, LOW);
  205. }
  206. }
  207.  
  208. ///////////////////////////////////////////////////////////////////////////
  209. //
  210. // MOTION SENSOR
  211. //
  212. ///////////////////////////////////////////////////////////////////////////
  213.  
  214. /*
  215. Function called when a motion is detected/ended
  216. */
  217. void onMotionChanged() {
  218. g_motion_status = !g_motion_status;
  219. g_motion_change = true;
  220. }
  221.  
  222. /*
  223. Function called to publish the status of the motion sensor
  224. */
  225. void publishMotionStatus() {
  226. if (g_motion_status) {
  227. if (g_mqttClient.publish(TOPIC_MOTION_STATUS, PAYLOAD_ON, true)) {
  228. #ifdef DEBUG
  229. Serial.print(F("INFO: MQTT message publish succeeded. Topic: "));
  230. Serial.print(TOPIC_MOTION_STATUS);
  231. Serial.print(F(". Payload: "));
  232. Serial.println(PAYLOAD_ON);
  233. #endif
  234. } else {
  235. #ifdef DEBUG
  236. Serial.println(F("ERROR: MQTT message publish failed, either connection lost, or message too large"));
  237. #endif
  238. }
  239. } else {
  240. if (g_mqttClient.publish(TOPIC_MOTION_STATUS, PAYLOAD_OFF, true)) {
  241. #ifdef DEBUG
  242. Serial.print(F("INFO: MQTT message publish succeeded. Topic: "));
  243. Serial.print(TOPIC_MOTION_STATUS);
  244. Serial.print(F(". Payload: "));
  245. Serial.println(PAYLOAD_OFF);
  246. #endif
  247. } else {
  248. #ifdef DEBUG
  249. Serial.println(F("ERROR: MQTT message publish failed, either connection lost, or message too large"));
  250. #endif
  251. }
  252. }
  253. }
  254.  
  255. ///////////////////////////////////////////////////////////////////////////
  256. //
  257. // WIFI and TLS
  258. //
  259. ///////////////////////////////////////////////////////////////////////////
  260.  
  261. /*
  262. Function called to setup the connection to the Wi-Fi Access Point
  263. */
  264. void setupWifi() {
  265. delay(10);
  266. // attempt to connect to the Wi-Fi AP
  267. WiFi.mode(WIFI_STA);
  268. WiFi.begin(AP_SSID, AP_PASSWORD);
  269. // define the fixed IP address
  270. WiFi.config(IP, IP_GATEWAY, IP_SUBNET, IP_DNS);
  271.  
  272. while (WiFi.status() != WL_CONNECTED) {
  273. delay(500);
  274. }
  275.  
  276. #ifdef DEBUG
  277. Serial.println(F("INFO: Client is now connected to the Wi-Fi AP"));
  278. Serial.print(F("INFO: IP address: "));
  279. Serial.println(WiFi.localIP());
  280. #endif
  281.  
  282. #ifdef TLS
  283. verifyFingerprint();
  284. #endif
  285. }
  286.  
  287. /*
  288. Function called to verify the fingerprint of the MQTT server and establish a secure connection
  289. */
  290. #ifdef TLS
  291. void verifyFingerprint() {
  292. if (!g_wifiClient.connect(MQTT_SERVER_IP, MQTT_SERVER_PORT)) {
  293. #ifdef DEBUG
  294. Serial.println(F("ERROR: The connection failed to the secure MQTT server"));
  295. #endif
  296. return;
  297. }
  298.  
  299. if (g_wifiClient.verify(CA_FINGERPRINT, CA_SUBJECT)) {
  300. #ifdef DEBUG
  301. Serial.println(F("INFO: The connection is secure"));
  302. #endif
  303. } else {
  304. #ifdef DEBUG
  305. Serial.println(F("ERROR: The given certificate does't match"));
  306. #endif
  307. }
  308. }
  309. #endif
  310.  
  311. ///////////////////////////////////////////////////////////////////////////
  312. //
  313. // MQTT
  314. //
  315. ///////////////////////////////////////////////////////////////////////////
  316.  
  317. /*
  318. Function called when a MQTT message arrived
  319. @param p_topic The topic of the MQTT message
  320. @param p_payload The payload of the MQTT message
  321. @param p_length The length of the payload
  322. */
  323. void callback(char* p_topic, byte* p_payload, unsigned int p_length) {
  324. #ifdef DEBUG
  325. Serial.println(F("INFO: A new MQTT message arrived"));
  326. Serial.print(F("INFO: Topic: "));
  327. Serial.println(p_topic);
  328. Serial.print(F("INFO: Payload: "));
  329. for (int i = 0; i < p_length; i++) {
  330. Serial.print((char)p_payload[i]);
  331. }
  332. Serial.println();
  333. Serial.print(F("INFO: Length: "));
  334. Serial.println(p_length);
  335. #endif
  336. // handle the MQTT topic of the received message
  337. if (String(TOPIC_LIGHT1_COMMAND).equals(p_topic)) {
  338. // concat the payload into a string
  339. String payload;
  340. for (uint8_t i = 0; i < p_length; i++) {
  341. payload.concat((char)p_payload[i]);
  342. }
  343. if (payload.equals(String(PAYLOAD_ON))) {
  344. g_light1_status = true;
  345. setLight1Status();
  346. publishLight1Status();
  347. } else if (payload.equals(String(PAYLOAD_OFF))) {
  348. g_light1_status = false;
  349. setLight1Status();
  350. publishLight1Status();
  351. } else {
  352. #ifdef DEBUG
  353. Serial.println(F("ERROR: The payload of the MQTT message is not valid"));
  354. #endif
  355. }
  356. } else if (String(TOPIC_LIGHT2_COMMAND).equals(p_topic)) {
  357. // concat the payload into a string
  358. String payload;
  359. for (uint8_t i = 0; i < p_length; i++) {
  360. payload.concat((char)p_payload[i]);
  361. }
  362. if (payload.equals(String(PAYLOAD_ON))) {
  363. g_light2_status = true;
  364. setLight2Status();
  365. publishLight2Status();
  366. } else if (payload.equals(String(PAYLOAD_OFF))) {
  367. g_light2_status = false;
  368. setLight2Status();
  369. publishLight2Status();
  370. } else {
  371. #ifdef DEBUG
  372. Serial.println(F("ERROR: The payload of the MQTT message is not valid"));
  373. #endif
  374. }
  375. } else {
  376. // do nothing.....
  377. #ifdef DEBUG
  378. Serial.println(F("INFO: The received MQTT message was not used"));
  379. #endif
  380. }
  381. }
  382.  
  383. /*
  384. Function called to reconnect the client to the MQTT broker and publish/subscribe to/from some MQTT topics
  385. */
  386. void reconnect() {
  387. while (!g_mqttClient.connected()) {
  388. if (g_mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) {
  389. #ifdef DEBUG
  390. Serial.println(F("INFO: The client is successfully connected to the MQTT broker"));
  391. #endif
  392. // subscribe to the light1 command topic
  393. if (g_mqttClient.subscribe(TOPIC_LIGHT1_COMMAND)) {
  394. #ifdef DEBUG
  395. Serial.print(F("INFO: Sending the MQTT subscribe succeeded. Topic: "));
  396. Serial.println(TOPIC_LIGHT1_COMMAND);
  397. #endif
  398. } else {
  399. #ifdef DEBUG
  400. Serial.print(F("ERROR: Sending the MQTT subscribe failed. Topic: "));
  401. Serial.println(TOPIC_LIGHT1_COMMAND);
  402. #endif
  403. }
  404.  
  405. // subscribe to the light2 command topic
  406. if (g_mqttClient.subscribe(TOPIC_LIGHT2_COMMAND)) {
  407. #ifdef DEBUG
  408. Serial.print(F("INFO: Sending the MQTT subscribe succeeded. Topic: "));
  409. Serial.println(TOPIC_LIGHT2_COMMAND);
  410. #endif
  411. } else {
  412. #ifdef DEBUG
  413. Serial.print(F("ERROR: Sending the MQTT subscribe failed. Topic: "));
  414. Serial.println(TOPIC_LIGHT2_COMMAND);
  415. #endif
  416. }
  417.  
  418. // set the initial status of lights 1 & 2
  419. setLight1Status();
  420. setLight2Status();
  421.  
  422. // publish the initial status of lights 1 & 2
  423. publishLight1Status();
  424. publishLight2Status();
  425. } else {
  426. #ifdef DEBUG
  427. Serial.println(F("ERROR: The connection failed with the MQTT broker"));
  428. Serial.print("ERROR: rc: ");
  429. Serial.println(g_mqttClient.state());
  430. // wait 5 seconds before retrying
  431. delay(5000);
  432. #endif
  433. }
  434. }
  435. }
  436.  
  437. ///////////////////////////////////////////////////////////////////////////
  438. //
  439. // SETUP and LOOP
  440. //
  441. ///////////////////////////////////////////////////////////////////////////
  442.  
  443. /*
  444. Function called once to initialize the board
  445. */
  446. void setup() {
  447. #ifdef DEBUG
  448. Serial.begin(115200);
  449. Serial.println(F("\nINFO: The Wi-Fi module is starting..."));
  450. #endif
  451.  
  452. // init the LEDs as output, the motion sensor as input
  453. pinMode(LIGHT1_PIN, OUTPUT);
  454. pinMode(LIGHT2_PIN, OUTPUT);
  455. pinMode(MOTION_SENSOR_PIN, INPUT);
  456. attachInterrupt(digitalPinToInterrupt(MOTION_SENSOR_PIN), onMotionChanged, CHANGE);
  457. pinMode(BUILTIN_LED, OUTPUT); // the built-in LED is used to indicate a motion
  458. digitalWrite(BUILTIN_LED, HIGH); // turn off the built-in LED
  459.  
  460.  
  461. setupWifi();
  462.  
  463. // set the MQTT broker IP address and port
  464. g_mqttClient.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);
  465. // set the MQTT callback function
  466. g_mqttClient.setCallback(callback);
  467.  
  468. // set the hostname & password for OTA
  469. ArduinoOTA.setHostname(MQTT_CLIENT_ID);
  470. ArduinoOTA.setPassword(OTA_PASSWORD);
  471.  
  472. #ifdef DEBUG
  473. ArduinoOTA.onStart([]() {
  474. Serial.println(F("INFO: OTA starts"));
  475. });
  476. ArduinoOTA.onEnd([]() {
  477. Serial.println(F("INFO: OTA ends"));
  478. });
  479. ArduinoOTA.onError([](ota_error_t error) {
  480. Serial.println(F("INFO: An error occurs during OTA"));
  481. });
  482. #endif
  483. ArduinoOTA.begin();
  484.  
  485. // blink the internal LED to indicate the end of the startup
  486. digitalWrite(BUILTIN_LED, LOW);
  487. delay(100);
  488. digitalWrite(BUILTIN_LED, HIGH);
  489. delay(100);
  490. digitalWrite(BUILTIN_LED, LOW);
  491. delay(100);
  492. digitalWrite(BUILTIN_LED, HIGH);
  493. }
  494.  
  495. /*
  496. Function called infinitely after the setup function
  497. */
  498. void loop() {
  499. // keep the MQTT client connected to the broker
  500. if (!g_mqttClient.connected()) {
  501. reconnect();
  502. }
  503. g_mqttClient.loop();
  504.  
  505. yield();
  506.  
  507. ArduinoOTA.handle();
  508.  
  509. yield();
  510.  
  511. // test if the status of the motion sensor was changed by an interrupt
  512. if (g_motion_change) {
  513. publishMotionStatus();
  514. g_motion_change = false;
  515. if (g_motion_status) {
  516. digitalWrite(BUILTIN_LED, LOW); // turn on the built-in LED
  517. #ifdef DEBUG
  518. Serial.println(F("INFO: Motion detected"));
  519. #endif
  520. } else {
  521. digitalWrite(BUILTIN_LED, HIGH); // turn off the built-in LED
  522. #ifdef DEBUG
  523. Serial.println(F("INFO: Motion ended"));
  524. #endif
  525. }
  526. }
  527.  
  528. yield();
  529. }
  530. 0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement