#include #include #include #include #define ENCA 14 #define ENCB 13 #define ENC_DECODER (1 << 2) #include extern "C" { #include "ws2812_i2s.h" } const int LEDS_CNT = 16; const int CENTER_OFFSET = 11; const int MAX_VAL = 100; const int LED_MIN = 0; const int LED_MAX = 16; class EncoderEndpoint : public Endpoint { private: ClickEncoder encoder; //(ENCA, ENCB, 4, 4); struct __attribute__((packed)) { uint8_t g; uint8_t r; uint8_t b; } leds[LEDS_CNT]; Timer animationTimer; Timer delayedValueTimer; Timer encTimer; int delayedValue = 0; int value = 0; bool playing = false; long long lastInteraction; void publish(String key, String value) { if (parent->mqtt.getConnectionState() == eTCS_Connected) { parent->mqtt.publish( String(TOPIC_PREFIX "mopidy/status/") + key + String("/set"), value); } } void animate() { int oldval = value; value += encoder.getValue() * 3; value = constrain(value, 0, MAX_VAL); if (value != oldval) { lastInteraction = millis(); publish("volume", String(map(value, 0, MAX_VAL, 0, 100))); //parent->mqtt.publish(TOPIC_PREFIX "mopidy/status/volume/set", String(map(value, 0, MAX_VAL, 0, 100))); Serial.println(value); } int button = encoder.getButton(); if(button != 0) { Serial.print("button: "); Serial.println(button); if (button == 5) { publish("playing", playing ? "false" : "true"); } } for(int i = 0; i < LEDS_CNT; i++) { WDT.alive(); int v = constrain(map(value, MAX_VAL * (LEDS_CNT-i-1) / LEDS_CNT, MAX_VAL * (LEDS_CNT-i) / LEDS_CNT, LED_MIN, LED_MAX), LED_MIN, LED_MAX); int led_i = (i + CENTER_OFFSET) % LEDS_CNT; if(playing) { leds[led_i].g = v; leds[led_i].r = 0; leds[led_i].b = 0; } else { leds[led_i].g = 0; leds[led_i].r = v; leds[led_i].b = 0; } } ws2812_push((uint8_t*) leds, sizeof(leds)); } public: EncoderEndpoint() : Endpoint("analog"), encoder(ENCA, ENCB, 4, 4) { } void updateDelayedValue() { Serial.println("delayed value xD"); value = delayedValue; } void bind(String _name, SpejsNode* _parent) { Endpoint::bind(_name, _parent); delayedValueTimer.initializeMs(1500, TimerDelegate(&EncoderEndpoint::updateDelayedValue, this)); animationTimer.initializeMs(30, TimerDelegate(&EncoderEndpoint::animate, this)).start(); ws2812_init(); pinMode(12, OUTPUT); digitalWrite(12, LOW); pinMode(2, OUTPUT); digitalWrite(2, LOW); encoder.setAccelerationEnabled(false); encTimer.initializeMs(1, TimerDelegate(&ClickEncoder::service, &encoder)).start(); } EndpointResult onValue(String property, String rvalue) { Serial.print(property); Serial.print(" = "); Serial.println(value); value = rvalue.toInt(); // map(rvalue.toInt(), 0, 100, 0, MAX_VAL); return 200; } void onConnected() { parent->mqtt.subscribe(TOPIC_PREFIX "mopidy/#"); } void onMessage(String topic, String payload) { Endpoint::onMessage(topic, payload); Serial.println("status: got message"); Serial.printf("%s: %s\r\n", topic.c_str(), payload.c_str()); if (topic == TOPIC_PREFIX "mopidy/status/volume") { delayedValue = payload.toInt(); //map(payload.toInt(), 0, 100, 0, MAX_VAL); if(millis() - lastInteraction > 3000) { updateDelayedValue(); } else { delayedValueTimer.stop(); delayedValueTimer.start(false); } } else if (topic == TOPIC_PREFIX "mopidy/status/playing") { playing = payload == "true"; } } }; SpejsNode node("encoder"); void init() { node.init(); node.registerEndpoint("encoder", new EncoderEndpoint()); }