Advertisement
atuline

async-firexy

Mar 21st, 2020
776
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 14.98 KB | None | 0 0
  1. /* File: mqtt-firexy.ino
  2.  *  
  3.  * Originally Fire2012withPalette by: Mark Kriegsman
  4.  *
  5.  * Asynchronous MQTT modifications by: Andrew Tuline
  6.  *
  7.  * Modified date: October, 2019
  8.  *
  9.  * Here's Mark Kriegsman's Fire2012withpalette configured with asynchronous MQTT based messaging. This routine is different from the standard ethernet and MQTT programming
  10.  * in that it is non-blocking for both ethernet and MQTT broker connectivity.
  11.  *
  12.  * Setting: Down a winding ravine, I have lanterns spread along the banks of a river over the length of a football field. There is no power, WiFi or data that I can rely on.
  13.  * I've plugged a small router into a portable inverter and have setup a couple of WiFi extenders down the ravine. On my Android phone, I've installed an MQTT broker as well as
  14.  * an MQTT Control Panel for several ESP8266 based (and 18650 powered) lanterns.
  15.  *
  16.  * The lanterns are configured with asynchronous MQTT clients that receive commands from my Android phone. Those commands are translated to parameters that modify the fire2012 animation. Reception will be
  17.  * sporadic for the lanterns as I walk in and out of the ravine, and the asynchonous client on the ESP8266 ensures smooth animation whether or not the lanterns have access to WiFi or the MQTT broker.
  18.  *
  19.  *
  20.  * Topic Prefix: fire/
  21.  *
  22.  * Topic Function                   Widget      Topic   Value(s)  Description
  23.  * --------------                   ------      -----   -------   ---------------------------
  24.  *
  25.  * Device                           Combo box   device  0,1-9   Select All or a single device in the family.
  26.  * Brightness                       Slider      bri     0-255   Decrease/Increase brightness.
  27.  * Hue                              Slider      hue     0-255   Select palette base hue.
  28.  * Speed                            Slider      speed   10-100  Change speed of animation.
  29.  * Cooling                          Slider      cool    20-100  Change rate of cooling of flame.
  30.  * Sparking                         Slider      spark   50-100  Change rate of sparking of new flames.                        
  31.  *
  32.  *
  33.  * Sample Topic and Payload:     fire/bri    245
  34.  *
  35.  *
  36.  * The Android phone MQTT client is called 'IoT MQTT Panel Pro'.
  37.  * The Android phone MQTT broker is called 'MQTT Broker App'.
  38.  *
  39.  * Warning: The ESP8266 may require you to unplug and re-plug it in again after programming it before the wifi will work.
  40.  *
  41.  *
  42.  * To Add:
  43.  *
  44.  * Rotate/fixed hue
  45.  * Rotate hue speed
  46.  * Direction
  47.  * Reboot
  48.  * Optional sine wave of hue speed
  49.  *
  50.  *
  51.  * For more information, see: http://tuline.com/getting-started-with-esp8266-and-mqtt/
  52.  *
  53.  * Update:
  54.  *
  55.  * I am no longer using the PubSubclient library as mentioned in the above article. That library had 'blocking' issues which caused the loop to delay in the event
  56.  * of a disconnection from the MQTT broker. I am now using the async-mqtt-client library from:
  57.  *
  58.  * https://github.com/marvinroger/async-mqtt-client
  59.  *
  60.  */
  61.  
  62.  
  63. #include <ESP8266WiFi.h>                                        // Should be included when you install the ESP8266.
  64. #include <Ticker.h>
  65. #include <AsyncMqttClient.h>                                    // https://github.com/marvinroger/async-mqtt-client
  66.  
  67. #include "FastLED.h"                                            // https://github.com/FastLED/FastLED
  68.  
  69. #if FASTLED_VERSION < 3001000
  70. #error "Requires FastLED 3.1 or later; check github for latest code."
  71. #endif
  72.  
  73.  
  74. // WiFi Authentication -------------------------------------------------------------------------
  75.  
  76. // #define WIFI_SSID "arduinoled"                                  // Extended field network
  77. // #define WIFI_PASSWORD "afng2036"
  78.  
  79. #define WIFI_SSID "dlink-9843"                               // Central field network
  80. #define WIFI_PASSWORD "cwrgz86646"
  81.  
  82. // #define WIFI_SSID "WiFiPlus5041-2.4G"                           // Home office network
  83. // #define WIFI_PASSWORD "t84uw5hc29"
  84.  
  85. // MQTT Authentication -------------------------------------------------------------------------
  86.  
  87. #define MQTT_HOST IPAddress(192, 168, 0, 101)
  88.  
  89. #define MQTT_PORT 1883
  90. #define MQTT_USR "wmabzsy"
  91. #define MQTT_PWD "GT8Do3vkgWP5"
  92. #define STRANDID 30
  93.  
  94. // MQTT Information
  95.  
  96. const char *prefixtopic = "fire30/";
  97. const char* subscribetopic[] = {"device", "bri", "hue", "speed", "cool", "spark"};
  98.  
  99. char theVal[100];                                           // Used to reset our topic/payload comparison string.
  100. char message_buff[100];                                     // Used to convert raw payload characters to a string.
  101.  
  102. AsyncMqttClient mqttClient;
  103. Ticker mqttReconnectTimer;
  104.  
  105. WiFiEventHandler wifiConnectHandler;
  106. WiFiEventHandler wifiDisconnectHandler;
  107. Ticker wifiReconnectTimer;
  108.  
  109.  
  110. const uint8_t kMatrixWidth = 6;                               // Number of lengths.
  111. const uint8_t kMatrixHeight = 5;                              // How long each length is.
  112. const bool    kMatrixSerpentineLayout = true;                 // Using a serpentine layout.
  113.  
  114.  
  115. #define NUM_LEDS (kMatrixWidth * kMatrixHeight)
  116.  
  117. // Fixed definitions cannot change on the fly.
  118. #define LED_DT D5                                             // Data pin to connect to the strip.
  119. #define COLOR_ORDER GRB                                       // It's GRB for WS2812 and BGR for APA102.
  120. #define LED_TYPE WS2812                                       // Using APA102, WS2812, WS2801. Don't forget to modify LEDS.addLeds to suit.
  121.  
  122. uint8_t max_bright = 255;                                     // Overall brightness.
  123.  
  124. struct CRGB leds[NUM_LEDS];                                   // Initialize our LED array.
  125.  
  126. CRGBPalette16 currentPalette;
  127. CRGBPalette16 targetPalette;
  128. TBlendType    currentBlending = LINEARBLEND;                  // NOBLEND or LINEARBLEND
  129.  
  130.  
  131. uint8_t mydevice = STRANDID;                                   // This is our STRANDID
  132. uint8_t mybri = 255;
  133. uint8_t myhue = 0;
  134. uint8_t myspeed = 40;
  135.  
  136. uint8_t   mypayload = 0;
  137.  
  138. uint8_t mycool = 40;                                          // Default 55, suggested range 20-100
  139. uint8_t myspark = 60;                                         // Default 120, suggested range 50-200.
  140.  
  141.  
  142.  
  143. // -------------------- Start of Code ----------------------------------------
  144.  
  145. void connectToWifi() {
  146.   Serial.println("Connecting to Wi-Fi...");
  147.   WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  148. } // connectToWifi()
  149.  
  150.  
  151.  
  152. void onWifiConnect(const WiFiEventStationModeGotIP& event) {
  153.   Serial.println("Connected to Wi-Fi.");
  154.   connectToMqtt();
  155. } // onWifiConnect()
  156.  
  157.  
  158.  
  159. void onWifiDisconnect(const WiFiEventStationModeDisconnected& event) {
  160.   Serial.println("Disconnected from Wi-Fi.");
  161.   mqttReconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
  162.   wifiReconnectTimer.once(2, connectToWifi);
  163. } // onWifiDisconnect()
  164.  
  165.  
  166.  
  167. void connectToMqtt() {
  168.   Serial.println("Connecting to MQTT...");
  169.   mqttClient.setCredentials(MQTT_USR, MQTT_PWD);
  170.   mqttClient.setServer(MQTT_HOST, MQTT_PORT);
  171.   mqttClient.connect();
  172. } // connectToMqtt()
  173.  
  174.  
  175.  
  176. void onMqttConnect(bool sessionPresent) {
  177.  
  178.   Serial.println("Connected to MQTT.");
  179.   Serial.print("Session present: ");
  180.   Serial.println(sessionPresent);
  181.  
  182. // Here is where we subscribe to the list of topics. . prepended by the prefix of course.
  183.   for (int i = 0; i < (sizeof(subscribetopic)/sizeof(int)); i++) {                        // Subscribes to list of topics from the MQTT broker. This whole loop is well above my pay grade.
  184.     String mypref =  prefixtopic;                                                         // But first, we need to get our prefix.
  185.     mypref.concat(subscribetopic[i]);                                                     // Concatenate prefix and the topic together with a little bit of pfm.
  186.     uint16_t packetIdSub = mqttClient.subscribe((char *) mypref.c_str(), 2);
  187.     Serial.print("Subscribing at QoS 2, packetId: ");
  188.     Serial.println(packetIdSub);                                                          // Let's print out each subscribed topic, just to be safe.
  189.   }
  190.    
  191. } // onMqttConnect()
  192.  
  193.  
  194.  
  195. void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
  196.   Serial.println("Disconnected from MQTT.");
  197.   if (WiFi.isConnected()) {
  198.     mqttReconnectTimer.once(2, connectToMqtt);
  199.   }
  200. } // onMqttDisconnect()
  201.  
  202.  
  203.  
  204. void onMqttSubscribe(uint16_t packetId, uint8_t qos) {
  205.   Serial.println("Subscribe acknowledged.");
  206.   Serial.print("  packetId: ");
  207.   Serial.println(packetId);
  208.   Serial.print("  qos: ");
  209.   Serial.println(qos);
  210. } // onMqttSubscribe()
  211.  
  212.  
  213.  
  214. void onMqttUnsubscribe(uint16_t packetId) {
  215.   Serial.println("Unsubscribe acknowledged.");
  216.   Serial.print("  packetId: ");
  217.   Serial.println(packetId);
  218. } // onMqttUnsubscribe()
  219.  
  220.  
  221.  
  222. void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
  223.  
  224.   int i; for (i = 0; i < len; i++) message_buff[i] = payload[i]; message_buff[i] = '\0';  // We copy payload to message_buff because we can't make a string out of payload.
  225.  
  226.   String msgString = String(message_buff);  
  227.   uint8_t msgVal = msgString.toInt();
  228.  
  229.   Serial.println("Publish received.");
  230.   Serial.print("  topic: ");
  231.   Serial.println(topic);
  232.   Serial.print("  msvVal: ");
  233.   Serial.println(msgVal);
  234.   Serial.print("  qos: ");
  235.   Serial.println(properties.qos);
  236.   Serial.print("  len: ");
  237.   Serial.println(len);
  238.  
  239.  
  240.  
  241.   strcpy(theVal, prefixtopic);
  242.   if (strcmp(topic, strcat(theVal, "device"))== 0) {                                                 // Device selector
  243.     mydevice = msgString.toInt();
  244.     Serial.print("device: "); Serial.println(mydevice);    
  245.   }
  246.  
  247.  
  248.   if (mydevice == 0 || mydevice == STRANDID) {
  249.  
  250.     strcpy(theVal, prefixtopic);
  251.     if (strcmp(topic, strcat(theVal,"bri")) == 0) {                                                 // Brightness
  252.       mybri = msgString.toInt();
  253.       Serial.print("mybri: "); Serial.println(mybri);
  254.     }
  255.    
  256.     strcpy(theVal, prefixtopic);
  257.     if (strcmp(topic, strcat(theVal,"hue"))== 0) {                                                   // Hue.
  258.       myhue = msgString.toInt();
  259.       Serial.print("myhue: "); Serial.println(myhue);
  260.       targetPalette = CRGBPalette16(CHSV(myhue, 255, 16), CHSV(myhue+8, 248, 64), CHSV(myhue+32, 224, 128), CHSV(myhue+64, 192, 255));
  261.     }
  262.  
  263.     strcpy(theVal, prefixtopic);
  264.     if (strcmp(topic, strcat(theVal,"speed"))== 0) {                                                 // Speed
  265.       myspeed = msgString.toInt();
  266.       Serial.print("myspeed: "); Serial.println(myspeed);
  267.     }
  268.  
  269.     strcpy(theVal, prefixtopic);
  270.     if (strcmp(topic, strcat(theVal,"cool"))== 0) {                                                 // Cooling
  271.       mycool = msgString.toInt();
  272.       Serial.print("mycool: "); Serial.println(mycool);
  273.     }
  274.  
  275.     strcpy(theVal, prefixtopic);
  276.     if (strcmp(topic, strcat(theVal,"spark"))== 0) {                                                // Sparking
  277.       myspark = msgString.toInt();
  278.       Serial.print("myspark: "); Serial.println(myspark);
  279.     }
  280.   } // if mydevice
  281.  
  282. } // onMqttMessage()
  283.  
  284.  
  285.  
  286. void onMqttPublish(uint16_t packetId) {
  287.   Serial.println("Publish acknowledged.");
  288.   Serial.print("  packetId: ");
  289.   Serial.println(packetId);
  290. } // onMqttPublish()
  291.  
  292.  
  293.  
  294. void setup() {
  295.  
  296.   Serial.begin(115200);
  297.   delay(1000);
  298.  
  299.   LEDS.addLeds<LED_TYPE, LED_DT, COLOR_ORDER>(leds, NUM_LEDS);                              // Use this for WS2812
  300. //  LEDS.addLeds<LED_TYPE, LED_DT, LED_CK, COLOR_ORDER>(leds, NUM_LEDS);                    // Use this for APA102
  301.  
  302.   FastLED.setBrightness(max_bright);
  303.   set_max_power_in_volts_and_milliamps(5, 500);                                             // FastLED Power management set at 5V, 500mA.
  304.  
  305.   currentPalette  = CRGBPalette16( CRGB::Black, CRGB::Red, CRGB::Orange, CRGB::Yellow);
  306.   targetPalette  = CRGBPalette16( CRGB::Black, CRGB::Red, CRGB::Orange, CRGB::Yellow);
  307.  
  308.  
  309.   wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnect);
  310.   wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect);
  311.  
  312.   mqttClient.onConnect(onMqttConnect);
  313.   mqttClient.onDisconnect(onMqttDisconnect);
  314.   mqttClient.onSubscribe(onMqttSubscribe);
  315.   mqttClient.onUnsubscribe(onMqttUnsubscribe);
  316.   mqttClient.onMessage(onMqttMessage);
  317.   mqttClient.onPublish(onMqttPublish);
  318.  
  319.   connectToWifi();
  320.  
  321. } // setup()
  322.  
  323.  
  324.  
  325. void Fire2012WithPalettexy() {
  326.  
  327.   static byte heat[kMatrixWidth][kMatrixHeight];                                              // Array of temperature readings at each simulation cell
  328.  
  329.   for (int mw = 0; mw < kMatrixWidth; mw++) {                                                 // Move along the width of the flame
  330.  
  331.     for (int mh = 0; mh < kMatrixHeight; mh++) {                                              // Step 1.  Cool down every cell a little
  332.       heat[mw][mh] = qsub8( heat[mw][mh],  random16(0, ((mycool * 10) / kMatrixHeight) + 2));
  333.     }
  334.  
  335.     for (int mh = kMatrixHeight - 1; mh >= 2; mh--) {                                         // Step 2.  Heat from each cell drifts 'up' and diffuses a little
  336.       heat[mw][mh] = (heat[mw][mh - 1] + heat[mw][mh - 2] + heat[mw][mh - 2] ) / 3;
  337.     }
  338.    
  339.     if (random8(0,255) < myspark ) {                                                          // Step 3.  Randomly ignite new 'sparks' of heat near the bottom
  340.       int mh = random8(3);
  341.       heat[mw][mh] = qadd8( heat[mw][mh], random8(160,255) );
  342.     }
  343.  
  344.     for (int mh = 0; mh < kMatrixHeight; mh++) {                                              // Step 4.  Map from heat cells to LED colors
  345.       byte colorindex = scale8( heat[mw][mh], 240);
  346.       leds[ XY(mh, mw)] = ColorFromPalette( targetPalette, colorindex, mybri, currentBlending);
  347.     }
  348.   } // for mw
  349.  
  350. } // Fire2012WithPalettexy()
  351.  
  352.  
  353.  
  354. uint16_t XY( uint8_t x, uint8_t y) {                                                      // x is height, y is width. Allows us to have 2 sided display.
  355.  
  356.   uint16_t i;
  357.  
  358.   if( kMatrixSerpentineLayout == false) {
  359.     i = (y * kMatrixHeight) + x;
  360.   }
  361.  
  362.   if( kMatrixSerpentineLayout == true) {
  363.     if( y & 0x01) {
  364.       // Odd rows run backwards
  365.       uint8_t reverseX = (kMatrixHeight - 1) - x;
  366.       i = (y * kMatrixHeight) + reverseX;
  367.     } else {
  368.       // Even rows run forwards
  369.       i = (y * kMatrixHeight) + x;
  370.     }
  371.   }
  372.   return i;
  373.  
  374. } // XY()
  375.  
  376.  
  377.  
  378. void loop() {
  379.  
  380.  EVERY_N_MILLISECONDS(100) {                                                               // FastLED based non-blocking FIXED delay.
  381.     uint8_t maxChanges = 24;
  382.     nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges);                  // Awesome palette blending capability.
  383.   }
  384.  
  385.   EVERY_N_MILLIS_I(thisTimer,50) {                                                          // This only sets the Initial timer delay. To change this value, you need to use thisTimer.setPeriod(); You could also call it thatTimer and so on.
  386.     thisTimer.setPeriod(myspeed);                                                           // Use that as our update timer value.
  387.     Fire2012WithPalettexy();
  388.   }
  389.  
  390.   FastLED.show();
  391.  
  392.  
  393. } // loop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement