Updated pingfuss.yaml and tabletenniscounter.yaml
This commit is contained in:
36
external_components/ws2812_table_tennis/__init__.py
Normal file
36
external_components/ws2812_table_tennis/__init__.py
Normal file
@ -0,0 +1,36 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import mqtt, number
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
ws2812_table_tennis_ns = cg.esphome_ns.namespace('ws2812_table_tennis')
|
||||
W2812Display = ws2812_table_tennis_ns.class_('CustomNumberDisplayComponent', mqtt.MQTTComponent, cg.Component)
|
||||
|
||||
DEPENDENCIES = ['mqtt', 'number']
|
||||
|
||||
#CONF_WS2812_PIN = "pin"
|
||||
#CONF_WS2812_RGB_MODE = "rgb_mode"
|
||||
|
||||
CONF_RED_NUM = "red_number"
|
||||
CONF_BLUE_NUM = "blue_number"
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema({
|
||||
cv.GenerateID(CONF_ID): cv.declare_id(W2812Display),
|
||||
cv.Required(CONF_RED_NUM): cv.use_id(number.Number),
|
||||
cv.Required(CONF_BLUE_NUM): cv.use_id(number.Number)
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
#yield cg.register_component(var, config)
|
||||
yield mqtt.register_mqtt_component(var, config)
|
||||
|
||||
red = yield cg.get_variable(config[CONF_RED_NUM])
|
||||
cg.add(var.set_red_number(red))
|
||||
|
||||
blue = yield cg.get_variable(config[CONF_BLUE_NUM])
|
||||
cg.add(var.set_blue_number(blue))
|
||||
|
||||
cg.add_library("makuna/NeoPixelBus", "2.7.3")
|
373
external_components/ws2812_table_tennis/tableTennisDisplay.h
Normal file
373
external_components/ws2812_table_tennis/tableTennisDisplay.h
Normal file
@ -0,0 +1,373 @@
|
||||
#include "esphome.h"
|
||||
#include "NeoPixelBus.h"
|
||||
//#include "multi_effect_handler.h"
|
||||
#define SEGMENT_LENGTH 5
|
||||
|
||||
namespace esphome {
|
||||
namespace ws2812_table_tennis {
|
||||
|
||||
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 mqtt::CustomMQTTDevice {
|
||||
protected:
|
||||
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)
|
||||
};
|
||||
|
||||
template_::TemplateNumber *redNum;
|
||||
template_::TemplateNumber *blueNum;
|
||||
|
||||
public:
|
||||
|
||||
void set_red_number(template_::TemplateNumber *redNum){
|
||||
this->redNum = redNum;
|
||||
}
|
||||
void set_blue_number(template_::TemplateNumber *blueNum){
|
||||
this->blueNum = blueNum;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
ESP_LOGD("TableTennisCounter", "Ready");
|
||||
}
|
||||
|
||||
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"];
|
||||
|
||||
redNum->publish_state(player1);
|
||||
blueNum->publish_state(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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user