espHome-NBS-files/cpp-files/tableTennisDisplay.h

356 lines
9.7 KiB
C++

#include "esphome.h"
#include "NeoPixelBus.h"
//#include "multi_effect_handler.h"
#define SEGMENT_LENGTH 5
class NbsEffect {
private:
int goalRed = 0, goalGreen = 0, goalBlue = 0;
double currentRed = 0, currentGreen = 0, currentBlue = 0;
double calcRed = 0, calcGreen = 0, calcBlue = 0;
int stepsPerSecond = 0;
int totalSteps = 0;
int currentStep = 0;
bool finalStep = true;
public:
NbsEffect(int stepsPerSecond_){
stepsPerSecond = stepsPerSecond_;
}
void setGoalColorAsRgb(int red, int green, int blue, int timeInMilliseconds){
if(goalRed == red && goalGreen == green && goalBlue == blue){
return;
}
finalStep = false;
currentRed = (double) goalRed;
currentGreen = (double) goalGreen;
currentBlue = (double) goalBlue;
goalRed = red;
goalGreen = green;
goalBlue = blue;
double timeInSeconds = (double) timeInMilliseconds / 1000.0;
totalSteps = (int) (timeInSeconds * (double) stepsPerSecond);
currentStep = totalSteps;
calcRed = ((double) goalRed - currentRed) / totalSteps;
calcGreen = ((double) goalGreen - currentGreen) / totalSteps;
calcBlue = ((double) goalBlue - currentBlue) / totalSteps;
currentStep = 0;
}
int debugGoalRed(){
return goalRed;
}
double debugCurrentRed(){
return currentRed;
}
double debugCalcRed(){
return calcRed;
}
bool step(){
if(currentStep >= totalSteps){
return false;
}
++currentStep;
if(currentStep == totalSteps){
currentRed = (double) goalRed;
currentGreen = (double) goalGreen;
currentBlue = (double) goalBlue;
finalStep = true;
return true;
}
currentRed += calcRed;
currentGreen += calcGreen;
currentBlue += calcBlue;
return true;
}
bool wasFinalStep(){
return finalStep;
}
int getCurrentRed(){
return (int) currentRed;
}
int getCurrentGreen(){
return (int) currentGreen;
}
int getCurrentBlue(){
return (int) currentBlue;
}
};
NeoPixelBus<NeoGrbFeature, NeoEsp8266BitBangWs2812xMethod> nbsStrip(143, D5);
class CustomNumberDisplayComponent : public Component, public CustomMQTTDevice {
const int middleSegment = SEGMENT_LENGTH * 14;
const int transitionLength = 500; // milliseconds
const int middleLength = 2;
const double brightness = 0.17;
NbsEffect *colorAnimation[4][7];
NbsEffect *middleSegmentAnim;
unsigned long lastUpdate = 0;
bool shouldShowNBS = true;
bool numbers[14][7] = {
{0, 1, 1, 1, 1, 1, 1}, // 0
{0, 1, 0, 0, 0, 0, 1}, // 1
{1, 1, 1, 0, 1, 1, 0}, // 2
{1, 1, 1, 0, 0, 1, 1}, // 3
{1, 1, 0, 1, 0, 0, 1}, // 4
{1, 0, 1, 1, 0, 1, 1}, // 5
{1, 0, 1, 1, 1, 1, 1}, // 6
{0, 1, 1, 0, 0, 0, 1}, // 7
{1, 1, 1, 1, 1, 1, 1}, // 8
{1, 1, 1, 1, 0, 1, 1}, // 9
{0, 0, 0, 0, 0, 0, 0}, // No Display (10)
{1, 0, 0, 0, 0, 0, 0}, // - (11)
{1, 0, 0, 0, 1, 0, 1}, // n (12)
{1, 0, 0, 1, 1, 1, 1} // b (13)
};
public:
void setup() override {
// Segment mapping
int segPixelCounter = 0;
for(int i = 0; i < 4; ++i){
for(int j = 0; j < 7; ++j){
colorAnimation[i][j] = new NbsEffect(40);
}
}
middleSegmentAnim = new NbsEffect(40);
nbsStrip.Begin();
setNumber(0, 12, 1.0, 0.0, 0.0);
setNumber(1, 13, 0.0, 1.0, 0.0);
setNumber(2, 5, 0.0, 0.0, 1.0);
setNumber(3, 11, 0.5, 0.5, 0.5);
for(int led = middleSegment; led < middleSegment + 2; ++led){
nbsStrip.SetPixelColor(led, RgbColor(0, 0, 0));
}
nbsStrip.Show();
lastUpdate = millis();
// also supports JSON messages
subscribe_json("tabletenniscounter/display/number/command", &CustomNumberDisplayComponent::on_json_message, 2);
}
void on_json_message(const std::string &topic, JsonObject root) {
//checker = 0;
if(!root.containsKey("state")){
return;
}
if(root["state"] != "ON"){
setNumber(0, 10);
setNumber(1, 10);
setNumber(2, 10);
setNumber(3, 10);
turnSegmentOff(middleSegmentAnim);
publish_json("tabletenniscounter/display/number/state", [=](JsonObject root2) {
root2["state"] = "OFF";
}, 2, false);
return;
}
if(shouldShowNBS){
shouldShowNBS = false;
lastUpdate = millis();
}
if (!root.containsKey("player1") || !root.containsKey("player2") || !(root.containsKey("player1Start") || root.containsKey("displayGreen"))){
setNumber(0, 12, 1.0, 0.0, 0.0);
setNumber(1, 13, 0.0, 1.0, 0.0);
setNumber(2, 5, 0.0, 0.0, 1.0);
setNumber(3, 11, 0.5, 0.5, 0.5);
turnSegmentOff(middleSegmentAnim);
publish_json("tabletenniscounter/display/number/state", [=](JsonObject root2) {
root2["state"] = "ON";
}, 2, false);
return;
}
int player1 = root["player1"];
int player2 = root["player2"];
id(red_num).set(player1);
id(blue_num).set(player2);
bool player1Start = root["player1Start"];
// do something with Json Object
if(player1 > 99) { player1 = 99; }
else if(player1 < 0) { player1 = 0; }
if(player2 > 99) { player2 = 99; }
else if(player2 < 0) { player2 = 0; }
int player1T = player1 / 10;
int player1O = player1 % 10;
int player2T = player2 / 10;
int player2O = player2 % 10;
int handleColorWinChange = 0;
if(root.containsKey("player1Winner")){
if(root["player1Winner"]){
handleColorWinChange = 1;
}
else{
handleColorWinChange = 2;
}
}
if(player1T == 0)
setNumber(0, 10);
else{
if(handleColorWinChange == 1){
setNumber(0, player1T, 1.0, 1.0, 0.0);
}else{
setNumber(0, player1T);
}
}
if(handleColorWinChange == 1){
setNumber(1, player1O, 1.0, 1.0, 0.0);
}else{
setNumber(1, player1O);
}
if(player2T == 0){
if(handleColorWinChange == 2){
setNumber(2, player2O, 1.0, 1.0, 0.0);
}else{
setNumber(2, player2O);
}
setNumber(3, 10);
}
else{
if(handleColorWinChange == 2){
setNumber(2, player2T, 1.0, 1.0, 0.0);
setNumber(3, player2O, 1.0, 1.0, 0.0);
}else{
setNumber(2, player2T);
setNumber(3, player2O);
}
}
if(root.containsKey("displayGreen")){
turnSegmentOn(middleSegmentAnim, brightness, 0.0, 1.0, 0.0);
}
else{
if(player1Start){
turnSegmentOn(middleSegmentAnim, brightness, 1.0, 0.0, 0.0);
}
else{
turnSegmentOn(middleSegmentAnim, brightness, 0.0, 0.0, 1.0);
}
}
// publish JSON using lambda syntax
publish_json("tabletenniscounter/display/number/state", [=](JsonObject root2) {
root2["state"] = "ON";
root2["player1"] = player1;
root2["player2"] = player2;
root2["player1Start"] = player1Start;
}, 2, false);
}
void loop() override{
if(lastUpdate + 25 >= millis()){
return;
}
if(lastUpdate + 50 < millis()){
//ESP_LOGW("custom_display", "LAGWARN, lastUpdate timer was reseted!");
lastUpdate = millis();
}
lastUpdate += 25;
bool didUpdate = false;
for(int i = 0; i < 4; ++i){
for(int j = 0; j < 7; ++j){
NbsEffect *effect = colorAnimation[i][j];
int segStart = calculateSegStart(i, j);
if(effect->step()){
didUpdate = true;
for(int led = segStart; led < segStart + SEGMENT_LENGTH; ++led){
nbsStrip.SetPixelColor(led, RgbColor(effect->getCurrentRed(), effect->getCurrentGreen(), effect->getCurrentBlue()));
}
}
}
}
if(colorAnimation[0][0]->wasFinalStep() && shouldShowNBS){
shouldShowNBS = false;
lastUpdate = millis() + 5000;
setNumber(0, 10, 0.0, 0.0, 0.0);
setNumber(1, 10, 0.0, 0.0, 0.0);
setNumber(2, 10, 0.0, 0.0, 0.0);
setNumber(3, 10, 0.0, 0.0, 0.0);
}
if(middleSegmentAnim->step()){
didUpdate = true;
//ESP_LOGD("custom", "#%d, Color Code: %d, %d, %d", checker++, middleSegmentAnim->getCurrentRed(), middleSegmentAnim->getCurrentGreen(), middleSegmentAnim->getCurrentBlue());
for(int led = middleSegment; led < middleSegment + 2; ++led){
nbsStrip.SetPixelColor(led, RgbColor(middleSegmentAnim->getCurrentRed(), middleSegmentAnim->getCurrentGreen(), middleSegmentAnim->getCurrentBlue()));
}
}
if(didUpdate){
nbsStrip.Show();
}
}
int calculateSegStart(int digit, int segment){
int start = (digit * SEGMENT_LENGTH * 7) + (segment * SEGMENT_LENGTH);
if(digit >= 2){
start += 2;
}
return start;
}
void turnSegmentOn(NbsEffect* segment, double brightness, double red, double green, double blue){
segment->setGoalColorAsRgb(makeColorAsInt(brightness, red, 220), makeColorAsInt(brightness, green, 170), makeColorAsInt(brightness, blue, 235), 500);
}
void turnSegmentOff(NbsEffect* segment){
segment->setGoalColorAsRgb(0, 0, 0, 500);
}
void setNumber(int digit, int number, double red, double green, double blue){
if(digit < 0 || digit > 3){
return;
}
for(int i = 0; i < 7; ++i){
if(numbers[number][i]){
turnSegmentOn(colorAnimation[digit][i], brightness, red, green, blue);
}
else{
turnSegmentOff(colorAnimation[digit][i]);
}
}
}
void setNumber(int digit, int number){
if(digit < 0 || digit > 3){
return;
}
double red = 0;
double blue = 0;
if(digit == 0 || digit == 1){
red = 1.0;
blue = 0.0;
}
else {
red = 0.0;
blue = 1.0;
}
setNumber(digit, number, red, 0.0, blue);
}
int makeColorAsInt(double brightness, double value, double colorMax){
return (int) (colorMax * value * brightness);
}
};