commit d488f5b30fc22388767ab771ebbd4cca7e8178bc Author: Julien Cabillot Date: Thu Mar 2 17:03:27 2017 +0100 import diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..36138a7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.vscode/* +mqttfastledmenu.h diff --git a/README.md b/README.md new file mode 100644 index 0000000..eb15109 --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +Introduction +============ + +Le but est d'avoir un selecteur d'effet + mode off. +Pour lancer l'effet sur le LED Strip@D1 (GPIO5) : +```bash +mosquitto_pub -d -u "" -P "" -t "" -m "ON" +``` +Pour l'arreter : +```bash +mosquitto_pub -d -u "" -P "" -t "" -m "OFF" +``` + +Un exemple de configuration pour home-assistant se trouve dans [ha_configuration.yml](ha\_configuration.yml). + +Matériel +======== + * 1x ESP8266 Lolin (Nodemcu v3) + * 1x Breadboard + * 1x Resistance 220Ω (jusqu'à 1kΩ) + * 1x Condensateur 1000μF + * 1x LED Strip wb2812b + * 1x Logic Level Translator + * 1x Transformateur AC-DC 220v-5v + +Médias +====== + +![Fritzing BreadBoard](mqttfastledmenu_bb.png) +![IRL](irl1.jpg) diff --git a/ha_configuration.yml b/ha_configuration.yml new file mode 100644 index 0000000..35783c1 --- /dev/null +++ b/ha_configuration.yml @@ -0,0 +1,50 @@ +# TODO : Il serait bien de pouvoir donner un nom joli sans envoyer de string +mqtt: + broker: "mqtt" + port: 1883 + client_id: "homeassistant1" + username: "***REMOVED***" + password: "***REMOVED***" + +input_select: + strip1_effect: + name: "Choix de l'effet" + options: + - 1 + - 2 + - 3 + - 4 + initial: 1 + +input_slider: + strip1_animation_speed: + name: "Strip1 Animation Speed" + initial: 120 + min: 10 + max: 150 + step: 10 + +automation: + - alias: "Strip1 Effect" + initial_state: True + hide_entity: False + trigger: + - platform: state + entity_id: input_select.strip1_effect + action: + - service: mqtt.publish + data_template: + topic: "strip1/seteffect" + payload: '{{ trigger.to_state.state | string }}' + retain: True + - alias: "Strip1 Animation Speed" + initial_state: True + hide_entity: False + trigger: + - platform: state + entity_id: input_slider.strip1_animation_speed + action: + - service: mqtt.publish + data_template: + topic: "strip1/setspeed" + payload: '{{ trigger.to_state.state | int }}' diff --git a/irl1.jpg b/irl1.jpg new file mode 100644 index 0000000..97aad95 Binary files /dev/null and b/irl1.jpg differ diff --git a/logo.jpg b/logo.jpg new file mode 100644 index 0000000..28ddb17 Binary files /dev/null and b/logo.jpg differ diff --git a/mqttfastledmenu.example.h b/mqttfastledmenu.example.h new file mode 100644 index 0000000..7c020f7 --- /dev/null +++ b/mqttfastledmenu.example.h @@ -0,0 +1,33 @@ +// LED +#define LED_NUM 300 +#define LED_PIN 5 // = D1 +#define LED_CHIPSET WS2812B +#define LED_COLOR_ORDER GRB +#define LED_BRIGHTNESS_DEFAULT 96 +#define LED_SPEED_DEFAULT 120 +#define LED_COLOR_DEFAULT CRGB::Red + +#define LED_EFFECT_OFF 1 +#define LED_EFFECT_CYLON 2 +#define LED_EFFECT_FULLRED 3 +#define LED_EFFECT_ERROR 4 + +// WIFI +#define WIFI_SSID "XXX" +#define WIFI_PASSWORD "XXX" + +// MQTT +#define MQTT_SERVER "XXX" +#define MQTT_PORT 1883 +#define MQTT_USER "XXX" +#define MQTT_PASS "XXX" + +#define MQTT_LED_EFFECT "strip1/seteffect" +#define MQTT_LED_BRIGHTNESS "strip1/setbrightness" +#define MQTT_LED_SPEED "strip1/setspeed" +#define MQTT_LED_COLOR "strip1/setcolor" + +// FastLED +// TODO : essayer, devrait limiter le flikering +//#define FASTLED_ALLOW_INTERRUPTS 0 +#define FASTLED_ESP8266_NODEMCU_PIN_ORDER diff --git a/mqttfastledmenu.fzz b/mqttfastledmenu.fzz new file mode 100644 index 0000000..196f488 Binary files /dev/null and b/mqttfastledmenu.fzz differ diff --git a/mqttfastledmenu.ino b/mqttfastledmenu.ino new file mode 100644 index 0000000..6804420 --- /dev/null +++ b/mqttfastledmenu.ino @@ -0,0 +1,227 @@ +#include "mqttfastledmenu_local.h" +#include "mqttfastledmenu.h" + +#include +#include +#include + +// LED +int brightness = LED_BRIGHTNESS_DEFAULT; +int color = LED_COLOR_DEFAULT; +int speed = LED_SPEED_DEFAULT; +CRGB leds[LED_NUM]; +int ledEffect = LED_EFFECT_OFF; + +// WIFI +WiFiClient espClient; + +// MQTT +char message_buff[100]; +PubSubClient client(espClient); + +void setup() { + Serial.begin(115200); + Serial.println("\nresetting"); + + // WIFI + setupWifi(); + + // MQTT + client.setServer(MQTT_SERVER, MQTT_PORT); + client.setCallback(callbackMQTT); + testConnectMQTT(); + client.subscribe(MQTT_LED_EFFECT); + client.subscribe(MQTT_LED_BRIGHTNESS); + client.subscribe(MQTT_LED_COLOR); + client.subscribe(MQTT_LED_SPEED); + + // LED + LEDS.addLeds(leds, LED_NUM).setCorrection(TypicalSMD5050); + FastLED.setBrightness(brightness); + ledBlackAll(); +} + +// WIFI +void setupWifi() { + Serial.print("Connexion a "); + Serial.print(WIFI_SSID); + WiFi.mode(WIFI_STA); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + + Serial.println(); + Serial.print("IP : "); + Serial.println(WiFi.localIP()); +} + +// MQTT +void testConnectMQTT() { + while (!client.connected()) { + Serial.print("Connexion au serveur MQTT... "); + if (client.connect("ESP8266Client", MQTT_USER, MQTT_PASS)) { + // TODO : doit-on se reconnecter aux topics ? + Serial.println("OK"); + } else { + Serial.print("KO, erreur : "); + Serial.print(client.state()); + Serial.println(", on attend 5 secondes avant de recommencer"); + delay(5000); + } + } +} + +// Déclenche les actions à la réception d'un message +void callbackMQTT(char* topic, byte* payload, unsigned int length) { + if (String(topic) == MQTT_LED_EFFECT) { + Serial.print("Received [" + String(topic) + "] : "); + + Serial.print(payload[0]); + Serial.print(" ~ "); + Serial.print(payload[0] - '0'); + + ledEffect = payload[0] - '0'; + Serial.print("["); + Serial.print(ledEffect); + Serial.println("]"); + + // Si on ne repasse pas tout à noir, cela peut faire des effets surprenants + ledBlackAll(); + } else if (String(topic) == MQTT_LED_BRIGHTNESS) { + unsigned int i = 0; + for(i = 0; i < length; i++) { + message_buff[i] = payload[i]; + } + message_buff[i] = '\0'; + // TODO : il est surement possible de faire plus propre + String msgString = String(message_buff); + brightness = msgString.toInt(); + FastLED.setBrightness(brightness); + + Serial.print("Received [" + String(topic) + "] : "); + Serial.println(msgString); + } else if (String(topic) == MQTT_LED_COLOR) { + unsigned int i = 0; + for(i = 0; i < length; i++) { + message_buff[i] = payload[i]; + } + message_buff[i] = '\0'; + String msgString = String(message_buff); + color = msgString.toInt(); + Serial.print("Received [" + String(topic) + "] : "); + Serial.println(msgString); + } else if (String(topic) == MQTT_LED_SPEED) { + unsigned int i = 0; + for(i = 0; i < length; i++) { + message_buff[i] = payload[i]; + } + message_buff[i] = '\0'; + String msgString = String(message_buff); + speed = msgString.toInt(); + Serial.print("Received [" + String(topic) + "] : "); + Serial.println(msgString); + } +} + +// LED +void ledBlackAll() +{ + FastLED.clear(); + FastLED.show(); + FastLED.delay(1000 / speed); +} + +void ledCylon() +{ + // Effet cylon : on allume une led, on attends, on eteinds, on passe à la suivante + // TODO : trop d'attente entre les clients.loop !!!! + for(int i = 0; i < LED_NUM; i++) { + if ((i % 10) == 0) { + client.loop(); + if (ledEffect != LED_EFFECT_CYLON) { + return; + } + } + + leds[i] = color; + FastLED.show(); + FastLED.delay(1000 / speed); + leds[i] = CRGB::Black; + FastLED.show(); + FastLED.delay(1000 / speed); + } + for(int i = LED_NUM - 1; i > 0; i--) { + if ((i % 10) == 0) { + client.loop(); + if (ledEffect != LED_EFFECT_CYLON) { + return; + } + } + + leds[i] = color; + FastLED.show(); + FastLED.delay(1000 / speed); + leds[i] = CRGB::Black; + FastLED.show(); + } + FastLED.delay(1000 / speed); +} + +void ledError() +{ + for(int i = 0; i < LED_NUM; i++) { + if ((i % 2) == 0) { + leds[i] = CRGB::Black; + } else { + leds[i] = color; + } + } + + FastLED.show(); + FastLED.delay(1000 / speed); +} + +// TODO : ne doit pas rester à terme, ça ne sert à rien de garder une fonction comme ça +void ledFullRed() +{ + fill_solid(leds, LED_NUM, color); + FastLED.show(); + FastLED.delay(1000 / speed); +} + +void loop() { + // MQTT + testConnectMQTT(); + client.loop(); + + EVERY_N_SECONDS(180) { + Serial.print("MQTT Subscribe refresh"); + client.subscribe(MQTT_LED_EFFECT); + client.subscribe(MQTT_LED_BRIGHTNESS); + client.subscribe(MQTT_LED_COLOR); + client.subscribe(MQTT_LED_SPEED); + Serial.println(" done"); + } + + // LED + switch(ledEffect) + { + case LED_EFFECT_OFF: + ledBlackAll(); + break; + case LED_EFFECT_CYLON: + ledCylon(); + break; + case LED_EFFECT_FULLRED: + ledFullRed(); + break; + default: + ledError(); + break; + } +} + +// TODO : regrouper input et select en un seul group, l'input enverrait directement Off et les effets ne seraient que effets diff --git a/mqttfastledmenu_bb.png b/mqttfastledmenu_bb.png new file mode 100644 index 0000000..91fb0eb Binary files /dev/null and b/mqttfastledmenu_bb.png differ