diff --git a/CompileHowto.md b/CompileHowto.md index aa7fb5f6..80bed57e 100644 --- a/CompileHowto.md +++ b/CompileHowto.md @@ -4,7 +4,7 @@ ``` sudo apt-get update -sudo apt-get install git cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev python-simplejson +sudo apt-get install git cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev ``` **ATTENTION Win10LinuxSubsystem** we do not (/we can't) support using hyperion in linux subsystem of MS Windows 10, albeit some users tested it with success. Keep in mind to disable diff --git a/assets/firmware/arduino/adalight/adalight.ino b/assets/firmware/arduino/adalight/adalight.ino index ea98cf93..8234aefb 100644 --- a/assets/firmware/arduino/adalight/adalight.ino +++ b/assets/firmware/arduino/adalight/adalight.ino @@ -11,6 +11,7 @@ #define INITIAL_LED_TEST_ENABLED true #define INITIAL_LED_TEST_BRIGHTNESS 32 // 0..255 +#define INITIAL_LED_TEST_TIME_MS 500 // 10.. // Number of leds in your strip. set to "1" and ANALOG_OUTPUT_ENABLED to "true" to activate analog only // As of 26/1/2017: @@ -137,7 +138,6 @@ void setup() { pinMode(ANALOG_GREEN_PIN, OUTPUT); } - // Uncomment/edit one of the following lines for your leds arrangement. int ledCount = MAX_LEDS; if (ANALOG_MODE == ANALOG_MODE_LAST_LED) { ledCount--; @@ -155,10 +155,17 @@ void setup() { // initial RGB flash #if INITIAL_LED_TEST_ENABLED == true - Serial.println("initial test"); - showColor(CRGB(INITIAL_LED_TEST_BRIGHTNESS, 0, 0)); delay(400); - showColor(CRGB(0, INITIAL_LED_TEST_BRIGHTNESS, 0)); delay(400); - showColor(CRGB(0, 0, INITIAL_LED_TEST_BRIGHTNESS )); delay(400); + for (int v=0;v +#include "FastLED.h" + +#define ANALOG_MODE_AVERAGE 0 +#define ANALOG_MODE_LAST_LED 1 -#include +/*==============================================================================*/ +/* LED und Arduino Variablen */ +/*==============================================================================*/ +#define INITIAL_LED_TEST_ENABLED true +#define INITIAL_LED_TEST_BRIGHTNESS 32 // 0..255 +#define INITIAL_LED_TEST_TIME_MS 500 // 0..255 -#define START_BYTE 0xC9 -#define STOP_BYTE 0x36 -#define DATA_FRAME 0xDA -#define COMMAND 0xC0 -#define REQ_RESP 0xAA +#define MAX_LEDS 400 // Number of LEDs +#define MAX_ARGS 10 // Max Number of command arguments +#define BAUDRATE 460800 // Baudrate +#define SERIAL Serial // Serial port for communication +#define NUM_LEDS_PER_STRIP 20 -#define BAUDRATE 115200 +// type of your led controller, possible values, see below +#define LED_TYPE WS2812B -#define DATA_PIN 12 -#define MAX_NR_LEDS 200 +// 3 wire (pwm): NEOPIXEL BTM1829 TM1812 TM1809 TM1804 TM1803 UCS1903 UCS1903B UCS1904 UCS2903 WS2812 WS2852 +// S2812B SK6812 SK6822 APA106 PL9823 WS2811 WS2813 APA104 WS2811_40 GW6205 GW6205_40 LPD1886 LPD1886_8BIT +// 4 wire (spi): LPD8806 WS2801 WS2803 SM16716 P9813 APA102 SK9822 DOTSTAR -CRGB leds[MAX_NR_LEDS]; +// For 3 wire led stripes line Neopixel/Ws2812, which have a data line, ground, and power, you just need to define DATA_PIN. +// For led chipsets that are SPI based (four wires - data, clock, ground, and power), both defines DATA_PIN and CLOCK_PIN are needed -enum States { - ST_START, - ST_PACKET_TYPE, - ST_PAYLOAD_SIZE, - ST_USER_DATA, - ST_END +// DATA_PIN, or DATA_PIN, CLOCK_PIN +#define LED_PINS 6 // 3 wire leds +//#define LED_PINS 6, 13 // 4 wire leds + +#define COLOR_ORDER GRB // colororder of the stripe, set RGB in hyperion + +#define OFF_TIMEOUT 15000 // ms to switch off after no data was received, set 0 to deactivate + +// analog rgb uni color led stripe - using of hyperion smoothing is recommended +// ATTENTION this pin config is default for atmega328 based arduinos, others might work to +// if you have flickering analog leds this might be caused by unsynced pwm signals +// try other pins is more or less the only thing that helps +#define ANALOG_OUTPUT_ENABLED false +#define ANALOG_MODE ANALOG_MODE_LAST_LED // use ANALOG_MODE_AVERAGE or ANALOG_MODE_LAST_LED +#define ANALOG_GROUND_PIN 8 // additional ground pin to make wiring a bit easier +#define ANALOG_RED_PIN 9 +#define ANALOG_GREEN_PIN 10 +#define ANALOG_BLUE_PIN 11 + +// overall color adjustments +#define ANALOG_BRIGHTNESS_RED 255 // maximum brightness for analog 0-255 +#define ANALOG_BRIGHTNESS_GREEN 255 // maximum brightness for analog 0-255 +#define ANALOG_BRIGHTNESS_BLUE 255 // maximum brightness for analog 0-255 + +#define BRIGHTNESS 255 // maximum brightness 0-255 +#define DITHER_MODE BINARY_DITHER // BINARY_DITHER or DISABLE_DITHER +#define COLOR_TEMPERATURE CRGB(255,255,255) // RGB value describing the color temperature +#define COLOR_CORRECTION TypicalLEDStrip // predefined fastled color correction +//#define COLOR_CORRECTION CRGB(255,255,255) // or RGB value describing the color correction + +// Baudrate, higher rate allows faster refresh rate and more LEDs +//#define serialRate 460800 // use 115200 for ftdi based boards +#define serialRate 115200 // use 115200 for ftdi based boards +//#define serialRate 500000 // use 115200 for ftdi based boards + + + +/*==============================================================================*/ +/* TPM2 Variablen */ +/*==============================================================================*/ + +enum Protocol +{ + // positions + posStart = 0, + posType = 1, + posFsHigh = 2, + posFsLow = 3, + posData = 4, + + // bytes + tpm2Start = 0xc9, + tpm2DataFrame = 0xda, + tpm2Command = 0xc0, + tpm2Answer = 0xaa, + tpm2End = 0x36, + tpm2Ack = 0xAC }; -States activeState = ST_START; -uint8_t byteRead = 0; -uint8_t payloadHighByte = 0; -uint8_t payloadLowByte = 0; -int payloadSize = 0; -int bytesRead = 0; -int nrOfLeds = 0; +enum Mode +{ + mNone, + mCommunication, + mProgram +}; -boolean flag = false; -void setup() { - // Init leds - for (int i = 0; i < MAX_NR_LEDS; i++) - leds[i] = 0; - // Start serial device - Serial.begin(BAUDRATE); - // Set time out for readBytes function - Serial.setTimeout(100); - // init fastLED Library - LEDS.addLeds(leds, MAX_NR_LEDS); - // setting brightness to 50% brightness - LEDS.setBrightness(128); - // debug led - pinMode(13, OUTPUT); +struct Data +{ + int pos; + uint8_t type; + uint16_t fs; + uint16_t maxSize; + uint8_t command; + CRGB rgb[MAX_LEDS]; +} data; + +byte args[MAX_ARGS]; +unsigned long lastDataAt = 0; +int program = 0; +int mode = mNone; +int effectDelay = 100; +static struct pt pt1; - for(;;) { - if (Serial.available() > 0) { - // process TPM2 protocol - switch (activeState) { - //------------------------------// - // START // - //------------------------------// - case ST_START: - // read incomming byte - byteRead = Serial.read(); - if (byteRead == START_BYTE) { - activeState = ST_PACKET_TYPE; - } - break; - //------------------------------// - // PACKET_TYPE // - //------------------------------// - case ST_PACKET_TYPE: - // read incomming byte - byteRead = Serial.read(); - if (byteRead == DATA_FRAME) { - activeState = ST_PAYLOAD_SIZE; - } else { - activeState = ST_START; - Serial.flush(); - } - break; - //------------------------------// - // PAYLOAD_SIZE // - //------------------------------// - case ST_PAYLOAD_SIZE: - payloadHighByte = Serial.read(); - while (Serial.available() == 0) {} - payloadLowByte = Serial.read(); - payloadSize = (payloadHighByte << 8) + payloadLowByte; - nrOfLeds = payloadSize / 3; - if (nrOfLeds <= MAX_NR_LEDS) { - activeState = ST_USER_DATA; - } else { - activeState = ST_START; - Serial.flush(); - } - break; - //------------------------------// - // USER_DATA // - //------------------------------// - case ST_USER_DATA: - bytesRead = Serial.readBytes((char *)leds, payloadSize); - LEDS.show(); - if (bytesRead == payloadSize) { - activeState = ST_END; - } else { - activeState = ST_START; - Serial.flush(); - } - break; - //------------------------------// - // END // - //------------------------------// - case ST_END: - // read incomming byte - byteRead = Serial.read(); - if (byteRead == STOP_BYTE) { - activeState = ST_START; - } else { - activeState = ST_START; - Serial.flush(); - } - break; - default: break; - } - } +// int freeRam() +// { +// extern int __heap_start, *__brkval; +// int v; +// return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); +// } +void setup() +{ + SERIAL.begin(BAUDRATE); + + delay(1000); + int ledCount = MAX_LEDS; + + if (ANALOG_MODE == ANALOG_MODE_LAST_LED) { + ledCount--; + } + + memset(data.rgb, 0, sizeof(struct CRGB) * ledCount); + + FastLED.addLeds(data.rgb, ledCount); + + // color adjustments + FastLED.setBrightness ( BRIGHTNESS ); + FastLED.setTemperature( COLOR_TEMPERATURE ); + FastLED.setCorrection ( COLOR_CORRECTION ); + FastLED.setDither ( DITHER_MODE ); + +#ifdef INITIAL_LED_TEST_ENABLED + for (int v=0;v0;i--){ + oneColorAll(i,i,i); + delayMicroseconds(PULSE-i*10); // wait + i--; + delay(0); //to prevent watchdog firing. + } + delay(REST); //take a rest... +} + +#endif + + oneColorAll(0,0,0); + + memset(args, 0, MAX_ARGS); + resetVars(); + PT_INIT(&pt1); + while (!SERIAL) { + ; // wait for serial port to connect. Needed for native USB } } -void loop() { +/*==============================================================================*/ +/* Thread für Programm/Effekte +/*==============================================================================*/ + +static int playProgramThread(struct pt *pt) +{ + static unsigned long timestamp = 0; + PT_BEGIN(pt); + while(1) + { + PT_WAIT_UNTIL(pt, millis() - timestamp > effectDelay); + playProgram(); + timestamp = millis(); + } + PT_END(pt); +} + +/*==============================================================================*/ +/* loop +/*==============================================================================*/ + +void loop() +{ + while (1) + { + // if data available switch to communication mode + if (SERIAL.available() > 0) + { + if (mode != mCommunication) + { + mode = mCommunication; + resetVars(); + } + doCommunication(); + } + else + // communication timeout after 0.5 seconds + while (SERIAL.available() == 0 && millis()-lastDataAt > 1000) + { + if (mode != mProgram) + { + mode = mProgram; + resetVars(); + } + else + playProgramThread(&pt1); + } + } +} + +/*==============================================================================*/ +/* do communication +/*==============================================================================*/ + +void doCommunication() +{ + // read ... + while (SERIAL.available() > 0) + { + + byte val = SERIAL.read(); + lastDataAt = millis(); + + if (data.pos == posStart && val == tpm2Start) // Startbyte + resetVars(); + + else if (data.pos == posType && (val == tpm2DataFrame || val == tpm2Command)) // Block-Art + data.type = val; + + else if (data.pos == posFsHigh) // Framesize (High Bit) + { + data.fs = (val << 8) & 0xFF00; + data.maxSize = data.fs; + } + else if (data.pos == posFsLow) // Framesize (Low byte) + { + data.fs += val & 0x00FF; + data.maxSize = data.fs; + if (data.fs > MAX_LEDS*3) // framsize too high + { + data.fs = MAX_LEDS*3; + } + + } + else if (data.pos == posData + data.maxSize && val == tpm2End) // End Byte + parsePacket(); + + else if (data.pos >= posData && data.pos < posData+data.fs) // Bytes zwischen Header und Ende lesen + evaluateData(val); + + else if (data.pos >= posData && data.pos < posData+data.maxSize) // Bytes zwischen Header und Ende lesen + continue; + + else // protocol violation ... + { + resetVars(); + continue; + } + data.pos++; + } + +} + +/*==============================================================================*/ +/* evaluate data +/*==============================================================================*/ + +void evaluateData(byte val) +{ + if (data.type == tpm2DataFrame) // frame data + { + uint8_t* rgb = (uint8_t*)data.rgb; + rgb[data.pos-posData] = val; + } + + else // command data + { + if (data.pos == posData) + { + data.command = val; + memset(args, 0, sizeof(args)); + } + else + args[data.pos-posData-1] = val; + } +} + +/*==============================================================================*/ +/* reset variables +/*==============================================================================*/ + +void resetVars() +{ + memset(&data, 0, sizeof(Data)); + //data.rgb = (struct CRGB*)FastSPI_LED.getRGBData(); + memset(data.rgb, 0, MAX_LEDS * sizeof(struct CRGB)); +} + +/*==============================================================================*/ +/* parse packet +/*==============================================================================*/ + +void parsePacket() +{ + switch (data.type) + { + case tpm2DataFrame: + { + showLeds(); + break; + } + case tpm2Command: + { + setProgram(); + break; + } + default: + break; + } + + SERIAL.write(tpm2Ack); + resetVars(); + data.pos = -1; +} + +/*==============================================================================*/ +/* set LED color +/*==============================================================================*/ + +void setLedColor(int led, uint8_t r, uint8_t g, uint8_t b) +{ + data.rgb[led].r = r; + data.rgb[led].g = g; + data.rgb[led].b = b; +} + +/*==============================================================================*/ +/* one Color All +/*==============================================================================*/ + +void oneColorAll(uint8_t r, uint8_t g, uint8_t b) +{ + memset(data.rgb, 0, MAX_LEDS * sizeof(struct CRGB)); + + for (int led = 0; led < MAX_LEDS; led++) + setLedColor(led, r, g, b); + + showLeds(); + effectDelay = 1000; +} + +/*==============================================================================*/ +/* Output Leds +/*==============================================================================*/ + +void showLeds() +{ + FastLED.show(); +} + + +void setProgram() +{ + program = data.command; +} + +void playProgram() +{ + switch (program) + { + case 0: oneColorAll(args[0],args[1],args[2]); break; + case 1: rainbow_loop(20); break; + default: oneColorAll(0,0,0); break; + } +} + +/* Set LED Color of given LED */ + +void oneColorAllNOSHOW(int r, int g, int b) +{ + resetVars(); + for (int led = 0; led < MAX_LEDS; led++) + { + setLedColor(led, r, g, b); + } + +} + +/*==============================================================================*/ +/* Effect 0: Fixed color - Arguments RR GG BB +/*==============================================================================*/ + +/*==============================================================================*/ +/* Effect 1: Loops rainbow colors around the stripe +/*==============================================================================*/ + +void rainbow_loop(int idelay) { //-LOOP HSV RAINBOW + static double idex = 0; + static double ihue = 0; + double steps = (double)255/MAX_LEDS; + + for(int led = 0 ; led < MAX_LEDS; led++ ) { + ihue = led * steps + idex; + if (ihue >= 255) + ihue -= 255; + + data.rgb[led] = CHSV((int)ihue, 255, 255); + + if (led == 0) + idex += steps; + if (idex >= 255) + idex = 0; + } + showLeds(); + effectDelay = idelay; } diff --git a/effects/schema/candle.schema.json b/effects/schema/candle.schema.json index b46c7862..54f9c1ca 100644 --- a/effects/schema/candle.schema.json +++ b/effects/schema/candle.schema.json @@ -1,68 +1,68 @@ { - "type":"object", - "script" : "candle.py", - "title":"edt_eff_candle_header_title", - "required":true, - "properties":{ - "candles": { - "type": "string", - "title":"edt_eff_whichleds_title", - "enum" : ["all","all-together","list"], - "default" : "all", - "options" : { - "enum_titles" : ["edt_eff_enum_all", "edt_eff_enum_all-together", "edt_eff_enum_list"] + "type":"object", + "script" : "candle.py", + "title":"edt_eff_candle_header_title", + "required":true, + "properties":{ + "candles": { + "type": "string", + "title":"edt_eff_whichleds_title", + "enum" : ["all","all-together","list"], + "default" : "all", + "options" : { + "enum_titles" : ["edt_eff_enum_all", "edt_eff_enum_all-together", "edt_eff_enum_list"] + }, + "propertyOrder" : 1 }, - "propertyOrder" : 1 + "ledlist": { + "type": "string", + "title":"edt_eff_ledlist_title", + "default" : "1,11,21", + "propertyOrder" : 2 + }, + "color": { + "type": "array", + "title":"edt_eff_color_title", + "format":"colorpicker", + "default": [255,138,0], + "items" : { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "minItems": 3, + "maxItems": 3, + "propertyOrder" : 3 + }, + "colorShift": { + "type": "number", + "title":"edt_eff_colorshift_title", + "default": 1, + "minimum" : 0, + "maximum": 30, + "append" : "edt_append_percent", + "propertyOrder" : 4 + }, + "brightness": { + "type": "number", + "title":"edt_eff_brightness_title", + "default": 100, + "minimum" : 1, + "maximum": 100, + "step" : 10, + "append" : "edt_append_percent", + "propertyOrder" : 5 + }, + "sleepTime": { + "type": "number", + "title":"edt_eff_sleeptime_title", + "default": 0.15, + "minimum" : 0.01, + "maximum": 1, + "step": 0.01, + "append" : "edt_append_s", + "propertyOrder" : 6 + } }, - "ledlist": { - "type": "string", - "title":"edt_eff_ledlist_title", - "default" : "1,11,21", - "propertyOrder" : 2 - }, - "color": { - "type": "array", - "title":"edt_eff_color_title", - "format":"colorpicker", - "default": [255,138,0], - "items" : { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "minItems": 3, - "maxItems": 3, - "propertyOrder" : 3 - }, - "colorShift": { - "type": "number", - "title":"edt_eff_colorshift_title", - "default": 1, - "minimum" : 0, - "maximum": 30, - "append" : "edt_append_percent", - "propertyOrder" : 4 - }, - "brightness": { - "type": "number", - "title":"edt_eff_brightness_title", - "default": 100, - "minimum" : 1, - "maximum": 100, - "step" : 10, - "append" : "edt_append_percent", - "propertyOrder" : 5 - }, - "sleepTime": { - "type": "number", - "title":"edt_eff_sleeptime_title", - "default": 0.15, - "minimum" : 0.01, - "maximum": 1, - "step": 0.01, - "append" : "edt_append_s", - "propertyOrder" : 6 - } - }, - "additionalProperties": false + "additionalProperties": false } diff --git a/effects/schema/clock.schema.json b/effects/schema/clock.schema.json index 3fc90061..296fe1d6 100644 --- a/effects/schema/clock.schema.json +++ b/effects/schema/clock.schema.json @@ -1,78 +1,78 @@ -{ - "type":"object", - "script" : "clock.py", - "title":"edt_eff_clock_header_title", - "required":true, - "properties":{ +{ + "type": "object", + "script": "clock.py", + "title": "edt_eff_clock_header_title", + "required": true, + "properties": { "offset": { "type": "number", - "title":"edt_eff_offset_title", + "title": "edt_eff_offset_title", "default": 0, - "append" : "edt_append_leds", - "propertyOrder" : 1 + "append": "edt_append_leds", + "propertyOrder": 1 }, "hour-color": { "type": "array", - "title":"edt_eff_colorHour_title", - "format":"colorpicker", - "default": [255,0,0], - "items" : { + "title": "edt_eff_colorHour_title", + "format": "colorpicker", + "default": [255, 0, 0], + "items": { "type": "integer", "minimum": 0, "maximum": 255 }, "minItems": 3, "maxItems": 3, - "propertyOrder" : 2 + "propertyOrder": 2 }, "minute-color": { "type": "array", - "title":"edt_eff_colorMinute_title", - "format":"colorpicker", - "default": [0,255,0], - "items" : { + "title": "edt_eff_colorMinute_title", + "format": "colorpicker", + "default": [0, 255, 0], + "items": { "type": "integer", "minimum": 0, "maximum": 255 }, "minItems": 3, "maxItems": 3, - "propertyOrder" : 3 + "propertyOrder": 3 }, "second-color": { "type": "array", - "title":"edt_eff_colorSecond_title", - "format":"colorpicker", - "default": [0,0,255], - "items" : { + "title": "edt_eff_colorSecond_title", + "format": "colorpicker", + "default": [0, 0, 255], + "items": { "type": "integer", "minimum": 0, "maximum": 255 }, "minItems": 3, "maxItems": 3, - "propertyOrder" : 4 + "propertyOrder": 4 }, "hour-margin": { "type": "number", - "title":"edt_eff_hourMargin_title", + "title": "edt_eff_hourMargin_title", "default": 2, - "append" : "edt_append_leds", - "propertyOrder" : 5 + "append": "edt_append_leds", + "propertyOrder": 5 }, "minute-margin": { "type": "number", - "title":"edt_eff_minuteMargin_title", + "title": "edt_eff_minuteMargin_title", "default": 1, - "append" : "edt_append_leds", - "propertyOrder" : 6 + "append": "edt_append_leds", + "propertyOrder": 6 }, "second-margin": { "type": "number", - "title":"edt_eff_secondMargin_title", + "title": "edt_eff_secondMargin_title", "default": 0, - "append" : "edt_append_leds", - "propertyOrder" : 7 + "append": "edt_append_leds", + "propertyOrder": 7 } }, "additionalProperties": false diff --git a/effects/schema/pacman.schema.json b/effects/schema/pacman.schema.json index 93895e3f..565ace83 100644 --- a/effects/schema/pacman.schema.json +++ b/effects/schema/pacman.schema.json @@ -1,4 +1,4 @@ -{ +{ "type":"object", "script" : "pacman.py", "title":"edt_eff_pacman_header_title", diff --git a/effects/schema/shutdown.schema.json b/effects/schema/shutdown.schema.json index dabf5684..d7f4da9d 100644 --- a/effects/schema/shutdown.schema.json +++ b/effects/schema/shutdown.schema.json @@ -40,11 +40,23 @@ "maxItems": 3, "propertyOrder" : 3 }, + "initial-blink": { + "type": "boolean", + "title":"edt_eff_initial_blink_title", + "default": true, + "propertyOrder" : 4 + }, + "set-post-color": { + "type": "boolean", + "title":"edt_eff_set_post_color_title", + "default": true, + "propertyOrder" : 5 + }, "shutdown-enabled": { "type": "boolean", "title":"edt_eff_enableshutdown_title", "default": false, - "propertyOrder" : 4 + "propertyOrder" : 6 } }, "additionalProperties": false diff --git a/effects/shutdown.json b/effects/shutdown.json index 7e09a13b..2e1ab45b 100644 --- a/effects/shutdown.json +++ b/effects/shutdown.json @@ -6,6 +6,8 @@ "speed" : 1.2, "alarm-color" : [255,0,0], "post-color" : [255,174,11], - "shutdown-enabled" : false + "shutdown-enabled" : false, + "initial-blink" : true, + "set-post-color" : true } } diff --git a/effects/shutdown.py b/effects/shutdown.py index 214af60e..12209988 100644 --- a/effects/shutdown.py +++ b/effects/shutdown.py @@ -13,21 +13,25 @@ sleepTime = float(hyperion.args.get('speed', 1.0))*0.5 alarmColor = hyperion.args.get('alarm-color', (255,0,0)) postColor = hyperion.args.get('post-color', (255,174,11)) off = bool(hyperion.args.get('shutdown-enabled', False)) +initialBlink = bool(hyperion.args.get('initial-blink', True)) +setPostColor = bool(hyperion.args.get('set-post-color', True)) + width = 12 height = 10 imageData = bytearray(height * width * (0,0,0)) # Start the write data loop -for i in range(6): - if hyperion.abort(): - off = False - break - if i % 2: - hyperion.setColor(alarmColor[0], alarmColor[1], alarmColor[2]) - else: - hyperion.setColor(0, 0, 0) - time.sleep(sleepTime) +if initialBlink: + for i in range(6): + if hyperion.abort(): + off = False + break + if i % 2: + hyperion.setColor(alarmColor[0], alarmColor[1], alarmColor[2]) + else: + hyperion.setColor(0, 0, 0) + time.sleep(sleepTime) for y in range(height,0,-1): if hyperion.abort(): @@ -39,11 +43,12 @@ for y in range(height,0,-1): time.sleep(sleepTime) time.sleep(1) -for y in range(height): - for x in range(width): - setPixel(x, y, postColor) -hyperion.setImage(width, height, imageData) -time.sleep(2) +if setPostColor: + for y in range(height): + for x in range(width): + setPixel(x, y, postColor) + hyperion.setImage(width, height, imageData) + time.sleep(2) if off and not hyperion.abort(): subprocess.call("halt") diff --git a/libsrc/leddevice/LedDeviceAdalight.cpp b/libsrc/leddevice/LedDeviceAdalight.cpp index f25e884d..ac59652a 100644 --- a/libsrc/leddevice/LedDeviceAdalight.cpp +++ b/libsrc/leddevice/LedDeviceAdalight.cpp @@ -6,6 +6,7 @@ LedDeviceAdalight::LedDeviceAdalight(const QJsonObject &deviceConfig) , _ligthBerryAPA102Mode(false) { _deviceReady = init(deviceConfig); + connect(this,SIGNAL(receivedData(QByteArray)),this,SLOT(receivedData(QByteArray))); } LedDevice* LedDeviceAdalight::construct(const QJsonObject &deviceConfig) @@ -74,3 +75,7 @@ int LedDeviceAdalight::write(const std::vector & ledValues) return writeBytes(_ledBuffer.size(), _ledBuffer.data()); } +void LedDeviceAdalight::receivedData(QByteArray data) +{ + Debug(_log, ">>received %d bytes data", data.size()); +} diff --git a/libsrc/leddevice/LedDeviceAdalight.h b/libsrc/leddevice/LedDeviceAdalight.h index 765f4586..23d1d163 100644 --- a/libsrc/leddevice/LedDeviceAdalight.h +++ b/libsrc/leddevice/LedDeviceAdalight.h @@ -22,6 +22,9 @@ public: virtual bool init(const QJsonObject &deviceConfig); +public slots: + void receivedData(QByteArray data); + private: /// /// Writes the led color values to the led-device @@ -32,6 +35,6 @@ private: virtual int write(const std::vector & ledValues); const short _headerSize; - bool _ligthBerryAPA102Mode; + bool _ligthBerryAPA102Mode; }; diff --git a/libsrc/leddevice/LedDeviceDMX.cpp b/libsrc/leddevice/LedDeviceDMX.cpp index 1c793d21..13709504 100644 --- a/libsrc/leddevice/LedDeviceDMX.cpp +++ b/libsrc/leddevice/LedDeviceDMX.cpp @@ -9,8 +9,14 @@ LedDeviceDMX::LedDeviceDMX(const QJsonObject &deviceConfig) , _dmxSlotsPerLed(3) , _dmxLedCount(0) , _dmxChannelCount(0) +{ + _deviceReady = init(deviceConfig); +} + +bool LedDeviceDMX::init(const QJsonObject &deviceConfig) { ProviderRs232::init(deviceConfig); + std::string _dmxString = deviceConfig["dmxdevice"].toString("invalid").toStdString(); if (_dmxString == "raw") { @@ -40,6 +46,8 @@ LedDeviceDMX::LedDeviceDMX(const QJsonObject &deviceConfig) _ledBuffer.resize(_dmxChannelCount, 0); _ledBuffer[0] = 0x00; // NULL START code + + return true; } LedDevice* LedDeviceDMX::construct(const QJsonObject &deviceConfig) diff --git a/libsrc/leddevice/LedDeviceDMX.h b/libsrc/leddevice/LedDeviceDMX.h index ee9de606..c4f20d69 100644 --- a/libsrc/leddevice/LedDeviceDMX.h +++ b/libsrc/leddevice/LedDeviceDMX.h @@ -18,6 +18,8 @@ public: /// constructs leddevice static LedDevice* construct(const QJsonObject &deviceConfig); + + virtual bool init(const QJsonObject &deviceConfig); private: /// diff --git a/libsrc/leddevice/LedDeviceFadeCandy.cpp b/libsrc/leddevice/LedDeviceFadeCandy.cpp index 1374d093..b924b53f 100644 --- a/libsrc/leddevice/LedDeviceFadeCandy.cpp +++ b/libsrc/leddevice/LedDeviceFadeCandy.cpp @@ -51,9 +51,9 @@ bool LedDeviceFadeCandy::init(const QJsonObject &deviceConfig) const QJsonArray whitePointConfig = deviceConfig["whitePoint"].toArray(); if ( !whitePointConfig.isEmpty() && whitePointConfig.size() == 3 ) { - _whitePoint_r = whitePointConfig[0].toDouble(); - _whitePoint_g = whitePointConfig[1].toDouble(); - _whitePoint_b = whitePointConfig[2].toDouble(); + _whitePoint_r = whitePointConfig[0].toDouble() / 255.0; + _whitePoint_g = whitePointConfig[1].toDouble() / 255.0; + _whitePoint_b = whitePointConfig[2].toDouble() / 255.0; } _opc_data.resize( _ledRGBCount + OPC_HEADER_SIZE ); diff --git a/libsrc/leddevice/LedDeviceSedu.cpp b/libsrc/leddevice/LedDeviceSedu.cpp index 304fe9ff..36d86e7d 100644 --- a/libsrc/leddevice/LedDeviceSedu.cpp +++ b/libsrc/leddevice/LedDeviceSedu.cpp @@ -20,7 +20,7 @@ LedDevice* LedDeviceSedu::construct(const QJsonObject &deviceConfig) bool LedDeviceSedu::init(const QJsonObject &deviceConfig) { ProviderRs232::init(deviceConfig); - + std::vector frameSpecs{{0xA1, 256}, {0xA2, 512}, {0xB0, 768}, {0xB1, 1536}, {0xB2, 3072} }; for (const FrameSpec& frameSpec : frameSpecs) diff --git a/libsrc/leddevice/ProviderRs232.cpp b/libsrc/leddevice/ProviderRs232.cpp index 654dbdc3..4cf6b726 100644 --- a/libsrc/leddevice/ProviderRs232.cpp +++ b/libsrc/leddevice/ProviderRs232.cpp @@ -5,6 +5,9 @@ // Qt includes #include +#include +#include +#include // Local Hyperion includes #include "ProviderRs232.h" @@ -17,6 +20,9 @@ ProviderRs232::ProviderRs232() , _bytesWritten(0) , _frameDropCounter(0) , _lastError(QSerialPort::NoError) + , _preOpenDelayTimeOut(0) + , _preOpenDelay(2000) + , _enableAutoDeviceName(false) { connect(&_rs232Port, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(error(QSerialPort::SerialPortError))); connect(&_rs232Port, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWritten(qint64))); @@ -29,13 +35,30 @@ bool ProviderRs232::init(const QJsonObject &deviceConfig) LedDevice::init(deviceConfig); - _deviceName = deviceConfig["output"].toString().toStdString(); + _deviceName = deviceConfig["output"].toString("auto"); + _enableAutoDeviceName = _deviceName == "auto"; _baudRate_Hz = deviceConfig["rate"].toInt(); - _delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(250); + _delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(1500); + _preOpenDelay = deviceConfig["delayBeforeConnect"].toInt(1500); return true; } +QString ProviderRs232::findSerialDevice() +{ + // take first available usb serial port - currently no probing! + for( auto port : QSerialPortInfo::availablePorts()) + { + if (port.hasProductIdentifier() && port.hasVendorIdentifier() && !port.isBusy()) + { + Info(_log, "found serial device: %s", port.systemLocation().toLocal8Bit().constData()); + return port.systemLocation(); + break; + } + } + return ""; +} + void ProviderRs232::bytesWritten(qint64 bytes) { _bytesWritten += bytes; @@ -49,8 +72,8 @@ void ProviderRs232::bytesWritten(qint64 bytes) void ProviderRs232::readyRead() { - QByteArray data = _rs232Port.readAll(); - Debug(_log, "received %d bytes data", data.size()); + emit receivedData(_rs232Port.readAll()); + Debug(_log, "received data"); } @@ -66,7 +89,9 @@ void ProviderRs232::error(QSerialPort::SerialPortError error) case QSerialPort::DeviceNotFoundError: Error(_log, "An error occurred while attempting to open an non-existing device."); break; case QSerialPort::PermissionError: - Error(_log, "An error occurred while attempting to open an already opened device by another process or a user not having enough permission and credentials to open."); break; + Error(_log, "An error occurred while attempting to open an already opened device by another process or a user not having enough permission and credentials to open. Device disabled."); + _deviceReady = false; + break; case QSerialPort::OpenError: Error(_log, "An error occurred while attempting to open an already opened device in this object."); break; case QSerialPort::NotOpenError: @@ -84,10 +109,14 @@ void ProviderRs232::error(QSerialPort::SerialPortError error) case QSerialPort::ResourceError: Error(_log, "An I/O error occurred when a resource becomes unavailable, e.g. when the device is unexpectedly removed from the system."); break; case QSerialPort::UnsupportedOperationError: - Error(_log, "The requested device operation is not supported or prohibited by the running operating system."); break; + Error(_log, "The requested device operation is not supported or prohibited by the running operating system. Device disabled."); + _deviceReady = false; + break; case QSerialPort::TimeoutError: Error(_log, "A timeout error occurred."); break; - default: Error(_log,"An unidentified error occurred. (%d)", error); + default: + Error(_log,"An unidentified error occurred. Device disabled. (%d)", error); + _deviceReady = false; } _rs232Port.clearError(); closeDevice(); @@ -106,35 +135,60 @@ void ProviderRs232::closeDevice() if (_rs232Port.isOpen()) { _rs232Port.close(); - Debug(_log,"Close UART: %s", _deviceName.c_str()); + Debug(_log,"Close UART: %s", _deviceName.toLocal8Bit().constData()); } } int ProviderRs232::open() { - Info(_log, "Opening UART: %s", _deviceName.c_str()); - _rs232Port.setPortName(_deviceName.c_str()); - return tryOpen(_delayAfterConnect_ms) ? 0 : -1; } bool ProviderRs232::tryOpen(const int delayAfterConnect_ms) { + if (_deviceName.isEmpty() || _rs232Port.portName().isEmpty()) + { + if ( _enableAutoDeviceName ) + { + _deviceName = findSerialDevice(); + if ( _deviceName.isEmpty() ) + { + return false; + } + } + Info(_log, "Opening UART: %s", _deviceName.toLocal8Bit().constData()); + _rs232Port.setPortName(_deviceName); + } + if ( ! _rs232Port.isOpen() ) { - if ( ! _rs232Port.open(QIODevice::ReadWrite) ) + _frameDropCounter = 0; + if (QFile::exists(_deviceName)) { - if ( _stateChanged ) + if ( _preOpenDelayTimeOut > QDateTime::currentMSecsSinceEpoch() ) { - Error(_log, "Unable to open RS232 device (%s)", _deviceName.c_str()); - _stateChanged = false; + return false; } + if ( ! _rs232Port.open(QIODevice::ReadWrite) ) + { + if ( _stateChanged ) + { + Error(_log, "Unable to open RS232 device (%s)", _deviceName.toLocal8Bit().constData()); + _stateChanged = false; + } + return false; + } + Debug(_log, "Setting baud rate to %d", _baudRate_Hz); + _rs232Port.setBaudRate(_baudRate_Hz); + _stateChanged = true; + _preOpenDelayTimeOut = 0; + } + else + { + _preOpenDelayTimeOut = QDateTime::currentMSecsSinceEpoch() + _preOpenDelay; return false; } - Debug(_log, "Setting baud rate to %d", _baudRate_Hz); - _rs232Port.setBaudRate(_baudRate_Hz); - _stateChanged = true; } if (delayAfterConnect_ms > 0) diff --git a/libsrc/leddevice/ProviderRs232.h b/libsrc/leddevice/ProviderRs232.h index 9a78a3a1..a9aa3ca3 100644 --- a/libsrc/leddevice/ProviderRs232.h +++ b/libsrc/leddevice/ProviderRs232.h @@ -3,6 +3,7 @@ #include #include #include +#include // Leddevice includes #include @@ -39,6 +40,19 @@ public: /// int open(); +private slots: + /// Write the last data to the leds again + int rewriteLeds(); + + /// Unblock the device after a connection delay + void unblockAfterDelay(); + void error(QSerialPort::SerialPortError error); + void bytesWritten(qint64 bytes); + void readyRead(); + +signals: + void receivedData(QByteArray data); + protected: /** * Writes the given bytes to the RS232-device and @@ -52,22 +66,14 @@ protected: void closeDevice(); -private slots: - /// Write the last data to the leds again - int rewriteLeds(); + QString findSerialDevice(); - /// Unblock the device after a connection delay - void unblockAfterDelay(); - void error(QSerialPort::SerialPortError error); - void bytesWritten(qint64 bytes); - void readyRead(); - -protected: // tries to open device if not opened bool tryOpen(const int delayAfterConnect_ms); - + + /// The name of the output device - std::string _deviceName; + QString _deviceName; /// The used baudrate of the output device qint32 _baudRate_Hz; @@ -86,4 +92,7 @@ protected: qint64 _bytesWritten; qint64 _frameDropCounter; QSerialPort::SerialPortError _lastError; + qint64 _preOpenDelayTimeOut; + int _preOpenDelay; + bool _enableAutoDeviceName; }; diff --git a/libsrc/leddevice/schemas/schema-adalight.json b/libsrc/leddevice/schemas/schema-adalight.json index 9010b6ee..19946533 100644 --- a/libsrc/leddevice/schemas/schema-adalight.json +++ b/libsrc/leddevice/schemas/schema-adalight.json @@ -5,7 +5,7 @@ "output": { "type": "string", "title":"edt_dev_spec_outputPath_title", - "default":"/dev/ttyUSB0", + "default":"/dev/ttyACM0", "propertyOrder" : 1 }, "rate": { diff --git a/libsrc/leddevice/schemas/schema-atmo.json b/libsrc/leddevice/schemas/schema-atmo.json index 50b19adc..2526baef 100644 --- a/libsrc/leddevice/schemas/schema-atmo.json +++ b/libsrc/leddevice/schemas/schema-atmo.json @@ -5,6 +5,7 @@ "output": { "type": "string", "title":"edt_dev_spec_outputPath_title", + "default":"/dev/ttyUSB0", "propertyOrder" : 1 }, "rate": { diff --git a/libsrc/leddevice/schemas/schema-dmx.json b/libsrc/leddevice/schemas/schema-dmx.json index 9278352c..54f2815f 100644 --- a/libsrc/leddevice/schemas/schema-dmx.json +++ b/libsrc/leddevice/schemas/schema-dmx.json @@ -5,6 +5,7 @@ "output": { "type": "string", "title":"edt_dev_spec_outputPath_title", + "default":"/dev/ttyUSB0", "propertyOrder" : 1 }, "rate": { @@ -18,13 +19,6 @@ "title":"edt_dev_spec_delayAfterConnect_title", "default": 250, "propertyOrder" : 3 - }, - "rewriteTime": { - "type": "integer", - "title":"edt_dev_spec_rewriteTime_title", - "default": 5000, - "append" : "ms", - "propertyOrder" : 4 } }, "additionalProperties": true diff --git a/libsrc/leddevice/schemas/schema-fadecandy.json b/libsrc/leddevice/schemas/schema-fadecandy.json index 87c92e7c..0f9ae134 100644 --- a/libsrc/leddevice/schemas/schema-fadecandy.json +++ b/libsrc/leddevice/schemas/schema-fadecandy.json @@ -55,15 +55,15 @@ "type" : "array", "title" : "edt_dev_spec_whitepoint_title", "propertyOrder" : 9, - "default" : [1.0,1.0,1.0], + "default" : [255,255,255], "maxItems" : 3, "minItems" : 3, - "format" : "table", + "format" : "colorpicker", "items" : { - "type" : "number", - "minimum" : 0.0, - "maximum": 1.0, - "default" : 1.0 + "type" : "integer", + "minimum" : 0, + "maximum": 255, + "default" : 255 } } }, diff --git a/libsrc/leddevice/schemas/schema-sedu.json b/libsrc/leddevice/schemas/schema-sedu.json index b6dedd84..e297204b 100644 --- a/libsrc/leddevice/schemas/schema-sedu.json +++ b/libsrc/leddevice/schemas/schema-sedu.json @@ -5,6 +5,7 @@ "output": { "type": "string", "title":"edt_dev_spec_outputPath_title", + "default":"/dev/ttyACM0", "propertyOrder" : 1 }, "rate": { diff --git a/libsrc/leddevice/schemas/schema-tpm2.json b/libsrc/leddevice/schemas/schema-tpm2.json index b6dedd84..e297204b 100644 --- a/libsrc/leddevice/schemas/schema-tpm2.json +++ b/libsrc/leddevice/schemas/schema-tpm2.json @@ -5,6 +5,7 @@ "output": { "type": "string", "title":"edt_dev_spec_outputPath_title", + "default":"/dev/ttyACM0", "propertyOrder" : 1 }, "rate": { diff --git a/test/jsonchecks/checkeffects.py b/test/jsonchecks/checkeffects.py index 69f8787d..1a4295fc 100644 --- a/test/jsonchecks/checkeffects.py +++ b/test/jsonchecks/checkeffects.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -import simplejson, sys, glob +import json, sys, glob from os import path from jsonschema import Draft3Validator @@ -12,14 +12,14 @@ retval = 0 total = 0 errors = 0 with open("libsrc/effectengine/EffectDefinition.schema.json") as baseSchemaFile: - baseSchema = simplejson.load(baseSchemaFile) + baseSchema = json.loads(baseSchemaFile.read().decode('utf-8-sig')) baseValidator = Draft3Validator(baseSchema) for filename in glob.glob(jsonFiles+'/*.json'): with open(filename) as f: total += 1 msg = " check effect %s ... " % filename try: - effect = simplejson.load(f) + effect = json.loads(f.read().decode('utf-8-sig')) script = path.basename(effect['script']) if not path.exists(jsonFiles+'/'+script): raise ValueError('script file: '+script+' not found.') @@ -31,7 +31,7 @@ with open("libsrc/effectengine/EffectDefinition.schema.json") as baseSchemaFile: # validate against schema with open(schema) as s: - effectSchema = simplejson.load(s) + effectSchema = json.loads(s.read().decode('utf-8-sig')) Draft3Validator.check_schema(effectSchema) validator = Draft3Validator(effectSchema) baseValidator.validate(effect) diff --git a/test/jsonchecks/checkjson.py b/test/jsonchecks/checkjson.py index d1f8e477..b9233325 100644 --- a/test/jsonchecks/checkjson.py +++ b/test/jsonchecks/checkjson.py @@ -11,10 +11,10 @@ for filename in sys.argv[1:]: total += 1 msg = " check json %s ... " % filename try: - json.load(f) + json.loads(f.read().decode('utf-8-sig')) #print(msg + "ok") except ValueError as e: - print(msg + 'invalid') + print(msg + 'invalid ('+str(e)+')') retval = 1 errors += 1 diff --git a/test/jsonchecks/checkschema.py b/test/jsonchecks/checkschema.py index c7269149..29fca779 100644 --- a/test/jsonchecks/checkschema.py +++ b/test/jsonchecks/checkschema.py @@ -11,10 +11,10 @@ schemaFileName = sys.argv[2] try: with open(schemaFileName) as schemaFile: with open(jsonFileName) as jsonFile: - j = json.load(jsonFile) - validator = Draft3Validator(json.load(schemaFile)) + j = json.loads(jsonFile.read().decode('utf-8-sig')) + validator = Draft3Validator(json.loads(schemaFile.read().decode('utf-8-sig'))) validator.validate(j) -except Exception as e: +except Exception as e: print('validation error: '+jsonFileName + ' '+schemaFileName+' ('+str(e)+')') sys.exit(1)