155 lines
4.2 KiB
C++
155 lines
4.2 KiB
C++
#include <user_config.h>
|
|
#include <SmingCore/SmingCore.h>
|
|
#include <algorithm>
|
|
|
|
#include <SpejsNode.h>
|
|
|
|
#define ENCA 14
|
|
#define ENCB 13
|
|
|
|
#define ENC_DECODER (1 << 2)
|
|
#include <ClickEncoder.h>
|
|
|
|
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());
|
|
}
|