spejsiot/mopidy-control/app/application.cpp

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());
}