@@ -1,6 +0,0 @@
|
|||||||
[submodule "Arduino/McLighting/data/McLightingUI"]
|
|
||||||
path = Arduino/McLighting/data/McLightingUI
|
|
||||||
url = https://github.com/toblum/McLightingUI
|
|
||||||
[submodule "clients/web/McLightingUI"]
|
|
||||||
path = clients/web/McLightingUI
|
|
||||||
url = https://github.com/toblum/McLightingUI
|
|
||||||
@@ -747,7 +747,7 @@ void loop() {
|
|||||||
#endif
|
#endif
|
||||||
#if defined(ENABLE_HOMEASSISTANT)
|
#if defined(ENABLE_HOMEASSISTANT)
|
||||||
if(ha_send_data.active()) ha_send_data.detach();
|
if(ha_send_data.active()) ha_send_data.detach();
|
||||||
ha_send_data.once(5, tickerSendState);
|
ha_send_data.once(DELAY_MQTT_HA_MESSAGE, tickerSendState);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
+2696
-2696
File diff suppressed because one or more lines are too long
+236
-236
@@ -1,236 +1,236 @@
|
|||||||
#define USE_WS2812FX_DMA 0 // 0 = Used PIN is ignored & set to RX/GPIO3; 1 = Used PIN is ignored & set to TX/GPIO1; 2 = Used PIN is ignored & set to D4/GPIO2; Uses WS2812FX, see: https://github.com/kitesurfer1404/WS2812FX
|
#define USE_WS2812FX_DMA 0 // 0 = Used PIN is ignored & set to RX/GPIO3; 1 = Used PIN is ignored & set to TX/GPIO1; 2 = Used PIN is ignored & set to D4/GPIO2; Uses WS2812FX, see: https://github.com/kitesurfer1404/WS2812FX
|
||||||
// or comment it out
|
// or comment it out
|
||||||
#if defined(USE_WS2812FX_DMA)
|
#if defined(USE_WS2812FX_DMA)
|
||||||
#define MAXLEDS 384 // due to memory limit of esp8266 at the moment only 384 leds are supported in DMA Mode. More can crash if mqtt is used.
|
#define MAXLEDS 384 // due to memory limit of esp8266 at the moment only 384 leds are supported in DMA Mode. More can crash if mqtt is used.
|
||||||
#else
|
#else
|
||||||
#define MAXLEDS 4096
|
#define MAXLEDS 4096
|
||||||
#endif
|
#endif
|
||||||
// Neopixel
|
// Neopixel
|
||||||
#define LED_PIN 3 // PIN (15 / D8) where neopixel / WS2811 strip is attached; is configurable, if USE_WS2812FX_DMA is not defined. Just for the start
|
#define LED_PIN 3 // PIN (15 / D8) where neopixel / WS2811 strip is attached; is configurable, if USE_WS2812FX_DMA is not defined. Just for the start
|
||||||
#define NUMLEDS 50 // Number of leds in the; is configurable just for the start
|
#define NUMLEDS 50 // Number of leds in the; is configurable just for the start
|
||||||
#define RGBORDER "GRBW" // RGBOrder; is configurable just for the start
|
#define RGBORDER "GRBW" // RGBOrder; is configurable just for the start
|
||||||
#define FX_OPTIONS 48 // ws2812fx Options 48 = SIZE_SMALL + FADE_MEDIUM is configurable just for the start; for WS2812FX setSegment OPTIONS, see: https://github.com/kitesurfer1404/WS2812FX/blob/master/extras/WS2812FX%20Users%20Guide.md
|
#define FX_OPTIONS 48 // ws2812fx Options 48 = SIZE_SMALL + FADE_MEDIUM is configurable just for the start; for WS2812FX setSegment OPTIONS, see: https://github.com/kitesurfer1404/WS2812FX/blob/master/extras/WS2812FX%20Users%20Guide.md
|
||||||
//#define LED_TYPE_WS2811 // Uncomment, if LED type uses 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
|
//#define LED_TYPE_WS2811 // Uncomment, if LED type uses 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
|
||||||
#define LED_BUILTIN 2 // ESP-12F has the built in LED on GPIO2, see https://github.com/esp8266/Arduino/issues/2192
|
#define LED_BUILTIN 2 // ESP-12F has the built in LED on GPIO2, see https://github.com/esp8266/Arduino/issues/2192
|
||||||
char HOSTNAME[65] = "McLightingRGBW"; // Friedly hostname is configurable just for the start. Hostname should not contain spaces as this can break Home Assistant discovery if used.
|
char HOSTNAME[65] = "McLightingRGBW"; // Friedly hostname is configurable just for the start. Hostname should not contain spaces as this can break Home Assistant discovery if used.
|
||||||
|
|
||||||
#define ENABLE_OTA 1 // If defined, enable Arduino OTA code. If set to 0 enable Arduino OTA code, if set to 1 enable ESP8266HTTPUpdateServer OTA code.
|
#define ENABLE_OTA 1 // If defined, enable Arduino OTA code. If set to 0 enable Arduino OTA code, if set to 1 enable ESP8266HTTPUpdateServer OTA code.
|
||||||
#define ENABLE_MQTT 1 // If defined use MQTT OR AMQTT, if set to 0 enable MQTT client code, see: https://github.com/toblum/McLighting/wiki/MQTT-API, if set to 1, enable Async MQTT code, see: https://github.com/marvinroger/async-mqtt-client
|
#define ENABLE_MQTT 1 // If defined use MQTT OR AMQTT, if set to 0 enable MQTT client code, see: https://github.com/toblum/McLighting/wiki/MQTT-API, if set to 1, enable Async MQTT code, see: https://github.com/marvinroger/async-mqtt-client
|
||||||
//#define ENABLE_MQTT_HOSTNAME_CHIPID // Uncomment/comment to add ESPChipID to end of MQTT hostname
|
//#define ENABLE_MQTT_HOSTNAME_CHIPID // Uncomment/comment to add ESPChipID to end of MQTT hostname
|
||||||
//#define ENABLE_MQTT_INCLUDE_IP // uncomment/comment to add the IP-adress to the MQTT message
|
//#define ENABLE_MQTT_INCLUDE_IP // uncomment/comment to add the IP-adress to the MQTT message
|
||||||
#define ENABLE_HOMEASSISTANT // If defined, enable Homeassistant integration, ENABLE_MQTT must be active
|
#define ENABLE_HOMEASSISTANT // If defined, enable Homeassistant integration, ENABLE_MQTT must be active
|
||||||
#define MQTT_HOME_ASSISTANT_SUPPORT // If defined, use AMQTT and select Tools -> IwIP Variant -> Higher Bandwidth
|
#define MQTT_HOME_ASSISTANT_SUPPORT // If defined, use AMQTT and select Tools -> IwIP Variant -> Higher Bandwidth
|
||||||
//#define DISABLE_MQTT_OUT_ON_MQTT_IN // If defined, McLighting will not send back MQTT-out on MQTT-in regarding issue #67, does not change anything at the moment
|
#define DELAY_MQTT_HA_MESSAGE 5 // HA Status is send after DELAY_MQTT_HA_MESSAGE seconds, to save bandwith
|
||||||
|
|
||||||
//#define ENABLE_BUTTON 14 // If defined, enable button handling code, see: https://github.com/toblum/McLighting/wiki/Button-control, the value defines the input pin (14 / D5) for switching the LED strip on / off, connect this PIN to ground to trigger button.
|
//#define ENABLE_BUTTON 14 // If defined, enable button handling code, see: https://github.com/toblum/McLighting/wiki/Button-control, the value defines the input pin (14 / D5) for switching the LED strip on / off, connect this PIN to ground to trigger button.
|
||||||
//#define ENABLE_BUTTON_GY33 12 // If defined, enable button handling code for GY-33 color sensor to scan color. The value defines the input pin (12 / D6) for read color data with RGB sensor, connect this PIN to ground to trigger button.
|
//#define ENABLE_BUTTON_GY33 12 // If defined, enable button handling code for GY-33 color sensor to scan color. The value defines the input pin (12 / D6) for read color data with RGB sensor, connect this PIN to ground to trigger button.
|
||||||
//#define POWER_SUPPLY 12 // PIN (12 / D6) If defined, enable output to control external power supply
|
//#define POWER_SUPPLY 12 // PIN (12 / D6) If defined, enable output to control external power supply
|
||||||
#if defined(POWER_SUPPLY)
|
#if defined(POWER_SUPPLY)
|
||||||
#define POWER_ON HIGH // Define the output state to turn on the power supply, either HIGH or LOW. Opposite will be uses for power off.
|
#define POWER_ON HIGH // Define the output state to turn on the power supply, either HIGH or LOW. Opposite will be uses for power off.
|
||||||
#endif
|
#endif
|
||||||
#define ENABLE_REMOTE 13 // If defined, enable Remote Control via TSOP31238. The value defines the input pin (13 / D7) for TSOP31238 Out
|
#define ENABLE_REMOTE 13 // If defined, enable Remote Control via TSOP31238. The value defines the input pin (13 / D7) for TSOP31238 Out
|
||||||
|
|
||||||
#if defined(ENABLE_BUTTON_GY33)
|
#if defined(ENABLE_BUTTON_GY33)
|
||||||
#define GAMMA 2.5 // Gamma correction for GY-33 sensor
|
#define GAMMA 2.5 // Gamma correction for GY-33 sensor
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ENABLE_STATE_SAVE // If defined, load saved state on reboot and save state on SPIFFS
|
#define ENABLE_STATE_SAVE // If defined, load saved state on reboot and save state on SPIFFS
|
||||||
|
|
||||||
#define CUSTOM_WS2812FX_ANIMATIONS // uncomment and put animations in "custom_ws2812fx_animations.h"
|
#define CUSTOM_WS2812FX_ANIMATIONS // uncomment and put animations in "custom_ws2812fx_animations.h"
|
||||||
#define USE_HTML_MIN_GZ // uncomment for using index.htm & edit.htm from PROGMEM instead of SPIFFS
|
#define USE_HTML_MIN_GZ // uncomment for using index.htm & edit.htm from PROGMEM instead of SPIFFS
|
||||||
|
|
||||||
#define TRANS_COLOR_DELAY 5 // Delay for color transition
|
#define TRANS_COLOR_DELAY 5 // Delay for color transition
|
||||||
#define TRANS_DELAY 10 // Delay for brightness and speed transition
|
#define TRANS_DELAY 10 // Delay for brightness and speed transition
|
||||||
|
|
||||||
// Experimental: Enable transitions of color, brightness and speed. It does not work properly for all effects.
|
// Experimental: Enable transitions of color, brightness and speed. It does not work properly for all effects.
|
||||||
bool transEffectOverride = false;
|
bool transEffectOverride = false;
|
||||||
uint8_t trans_cnt = 0;
|
uint8_t trans_cnt = 0;
|
||||||
int trans_cnt_max = 0;
|
int trans_cnt_max = 0;
|
||||||
unsigned long colorFadeDelay = 0;
|
unsigned long colorFadeDelay = 0;
|
||||||
unsigned long brightnessFadeDelay = 0;
|
unsigned long brightnessFadeDelay = 0;
|
||||||
unsigned long speedFadeDelay = 0;
|
unsigned long speedFadeDelay = 0;
|
||||||
|
|
||||||
#if defined(CUSTOM_WS2812FX_ANIMATIONS)
|
#if defined(CUSTOM_WS2812FX_ANIMATIONS)
|
||||||
#define MULTICAST false
|
#define MULTICAST false
|
||||||
#define START_UNIVERSE 1 // First DMX Universe to listen for
|
#define START_UNIVERSE 1 // First DMX Universe to listen for
|
||||||
uint8_t END_UNIVERSE = START_UNIVERSE; // Total number of Universes to listen for, starting at UNIVERSE
|
uint8_t END_UNIVERSE = START_UNIVERSE; // Total number of Universes to listen for, starting at UNIVERSE
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
uint8_t prevsegment = 0;
|
uint8_t prevsegment = 0;
|
||||||
|
|
||||||
#if defined(ENABLE_REMOTE)
|
#if defined(ENABLE_REMOTE)
|
||||||
uint8_t selected_color = 1;
|
uint8_t selected_color = 1;
|
||||||
uint64_t last_remote_cmd;
|
uint64_t last_remote_cmd;
|
||||||
enum RMT_BTN {ON_OFF, MODE_UP, MODE_DOWN, RED_UP, RED_DOWN, GREEN_UP, GREEN_DOWN, BLUE_UP, BLUE_DOWN, WHITE_UP, WHITE_DOWN, BRIGHTNESS_UP, BRIGHTNESS_DOWN, SPEED_UP, SPEED_DOWN, COL_M, COL_B, COL_X, AUTOMODE, CUST_1, CUST_2, CUST_3, SEG_UP, SEG_DOWN, REPEATCMD, BTN_CNT};
|
enum RMT_BTN {ON_OFF, MODE_UP, MODE_DOWN, RED_UP, RED_DOWN, GREEN_UP, GREEN_DOWN, BLUE_UP, BLUE_DOWN, WHITE_UP, WHITE_DOWN, BRIGHTNESS_UP, BRIGHTNESS_DOWN, SPEED_UP, SPEED_DOWN, COL_M, COL_B, COL_X, AUTOMODE, CUST_1, CUST_2, CUST_3, SEG_UP, SEG_DOWN, REPEATCMD, BTN_CNT};
|
||||||
// Change your IR Commands here. You can see them in console, after you pressed a button on the remote
|
// Change your IR Commands here. You can see them in console, after you pressed a button on the remote
|
||||||
uint64_t rmt_commands[BTN_CNT] = {0xF7C03F, 0xF7708F, 0xF7F00F, 0xF720DF, 0xF710EF, 0xF7A05F, 0xF7906F, 0xF7609F, 0xF750AF, 0xF7E01F, 0xF7D02F, 0xF730CF, 0xF7B04F, 0xF748B7, 0xF7C837, 0xF700FF, 0xF7807F, 0xF740BF, 0xF708F7, 0xF78877, 0xF728D7, 0xF7A857, 0xF76897, 0xF7E817, 0xFFFFFFFFFFFFFFFF};
|
uint64_t rmt_commands[BTN_CNT] = {0xF7C03F, 0xF7708F, 0xF7F00F, 0xF720DF, 0xF710EF, 0xF7A05F, 0xF7906F, 0xF7609F, 0xF750AF, 0xF7E01F, 0xF7D02F, 0xF730CF, 0xF7B04F, 0xF748B7, 0xF7C837, 0xF700FF, 0xF7807F, 0xF740BF, 0xF708F7, 0xF78877, 0xF728D7, 0xF7A857, 0xF76897, 0xF7E817, 0xFFFFFFFFFFFFFFFF};
|
||||||
#endif
|
#endif
|
||||||
#define WIFIMGR_PORTAL_TIMEOUT 180
|
#define WIFIMGR_PORTAL_TIMEOUT 180
|
||||||
//#define WIFIMGR_SET_MANUAL_IP
|
//#define WIFIMGR_SET_MANUAL_IP
|
||||||
|
|
||||||
#if defined(WIFIMGR_SET_MANUAL_IP)
|
#if defined(WIFIMGR_SET_MANUAL_IP)
|
||||||
uint8_t _ip[4] = {192,168,0,128};
|
uint8_t _ip[4] = {192,168,0,128};
|
||||||
uint8_t _gw[4] = {192,168,0,1};
|
uint8_t _gw[4] = {192,168,0,1};
|
||||||
uint8_t _sn[4] = {255,255,255,0};
|
uint8_t _sn[4] = {255,255,255,0};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(MQTT_HOME_ASSISTANT_SUPPORT)
|
#if defined(MQTT_HOME_ASSISTANT_SUPPORT)
|
||||||
#define MQTT_HOME_ASSISTANT_0_87_SUPPORT // Comment if using HA version < 0.87
|
#define MQTT_HOME_ASSISTANT_0_87_SUPPORT // Comment if using HA version < 0.87
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(USE_WS2812FX_DMA) && (USE_WS2812FX_DMA < 0 || USE_WS2812FX_DMA > 2)
|
#if defined(USE_WS2812FX_DMA) && (USE_WS2812FX_DMA < 0 || USE_WS2812FX_DMA > 2)
|
||||||
#error "Definition of USE_WS2812FX_DMA is wrong!"
|
#error "Definition of USE_WS2812FX_DMA is wrong!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ENABLE_MQTT) and ENABLE_MQTT < 0 and ENABLE_MQTT > 1
|
#if defined(ENABLE_MQTT) and ENABLE_MQTT < 0 and ENABLE_MQTT > 1
|
||||||
#error "Definition of ENABLE_MQTT is wrong!"
|
#error "Definition of ENABLE_MQTT is wrong!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ENABLE_MQTT) and ENABLE_MQTT < 0 and ENABLE_MQTT > 1
|
#if defined(ENABLE_MQTT) and ENABLE_MQTT < 0 and ENABLE_MQTT > 1
|
||||||
#error "Definition of ENABLE_MQTT is wrong!"
|
#error "Definition of ENABLE_MQTT is wrong!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ENABLE_HOMEASSISTANT) and !defined(ENABLE_MQTT)
|
#if defined(ENABLE_HOMEASSISTANT) and !defined(ENABLE_MQTT)
|
||||||
#error "To use HA, you have to either enable PubCubClient or AsyncMQTT"
|
#error "To use HA, you have to either enable PubCubClient or AsyncMQTT"
|
||||||
#endif
|
#endif
|
||||||
#if !defined(ENABLE_HOMEASSISTANT) and defined(MQTT_HOME_ASSISTANT_SUPPORT)
|
#if !defined(ENABLE_HOMEASSISTANT) and defined(MQTT_HOME_ASSISTANT_SUPPORT)
|
||||||
#error "To use HA support, you have to either enable Homeassistant component"
|
#error "To use HA support, you have to either enable Homeassistant component"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// parameters for automatically cycling favorite patterns
|
// parameters for automatically cycling favorite patterns
|
||||||
uint32_t autoParams[][6] = { // main_color, back_color, xtra_color, speed, mode, duration (milliseconds)
|
uint32_t autoParams[][6] = { // main_color, back_color, xtra_color, speed, mode, duration (milliseconds)
|
||||||
{0x00ff0000, 0x0000ff00, 0x00000000, 200, 1, 5000}, // blink red/geen for 5 seconds
|
{0x00ff0000, 0x0000ff00, 0x00000000, 200, 1, 5000}, // blink red/geen for 5 seconds
|
||||||
{0x0000ff00, 0x000000ff, 0x00000000, 180, 3, 10000}, // wipe green/blue for 10 seconds
|
{0x0000ff00, 0x000000ff, 0x00000000, 180, 3, 10000}, // wipe green/blue for 10 seconds
|
||||||
{0x000000ff, 0x00ff0000, 0x00000000, 100, 14, 10000}, // dual scan blue on red for 10 seconds
|
{0x000000ff, 0x00ff0000, 0x00000000, 100, 14, 10000}, // dual scan blue on red for 10 seconds
|
||||||
{0x000000ff, 0x00ff0000, 0x00000000, 100, 45, 15000}, // fireworks blue/red for 15 seconds
|
{0x000000ff, 0x00ff0000, 0x00000000, 100, 45, 15000}, // fireworks blue/red for 15 seconds
|
||||||
{0x00ff0000, 0x0000ff00, 0x000000ff, 40, 54, 15000} // tricolor chase red/green/blue for 15 seconds
|
{0x00ff0000, 0x0000ff00, 0x000000ff, 40, 54, 15000} // tricolor chase red/green/blue for 15 seconds
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(ENABLE_MQTT)
|
#if defined(ENABLE_MQTT)
|
||||||
char mqtt_buf[80];
|
char mqtt_buf[80];
|
||||||
char mqtt_will_topic[sizeof(HOSTNAME) + 7]; // Topic 'will' will be:HOSTNAME "/status";
|
char mqtt_will_topic[sizeof(HOSTNAME) + 7]; // Topic 'will' will be:HOSTNAME "/status";
|
||||||
const char mqtt_will_payload[] = "OFFLINE";
|
const char mqtt_will_payload[] = "OFFLINE";
|
||||||
char mqtt_intopic[sizeof(HOSTNAME) + 3]; // Topic 'in' will be: <HOSTNAME>/in
|
char mqtt_intopic[sizeof(HOSTNAME) + 3]; // Topic 'in' will be: <HOSTNAME>/in
|
||||||
char mqtt_outtopic[sizeof(HOSTNAME) + 4]; // Topic 'out' will be: <HOSTNAME>/out
|
char mqtt_outtopic[sizeof(HOSTNAME) + 4]; // Topic 'out' will be: <HOSTNAME>/out
|
||||||
bool mqtt_lwt_boot_flag = true;
|
bool mqtt_lwt_boot_flag = true;
|
||||||
#if ENABLE_MQTT == 0
|
#if ENABLE_MQTT == 0
|
||||||
#define MQTT_MAX_PACKET_SIZE 512
|
#define MQTT_MAX_PACKET_SIZE 512
|
||||||
#define MQTT_MAX_RECONNECT_TRIES 4
|
#define MQTT_MAX_RECONNECT_TRIES 4
|
||||||
uint8_t mqtt_reconnect_retries = 0;
|
uint8_t mqtt_reconnect_retries = 0;
|
||||||
uint8_t qossub = 0; // PubSubClient can sub qos 0 or 1
|
uint8_t qossub = 0; // PubSubClient can sub qos 0 or 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLE_MQTT == 1
|
#if ENABLE_MQTT == 1
|
||||||
uint8_t qossub = 0; // AMQTT can sub qos 0 or 1 or 2
|
uint8_t qossub = 0; // AMQTT can sub qos 0 or 1 or 2
|
||||||
uint8_t qospub = 0; // AMQTT can pub qos 0 or 1 or 2
|
uint8_t qospub = 0; // AMQTT can pub qos 0 or 1 or 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ENABLE_HOMEASSISTANT)
|
#if defined(ENABLE_HOMEASSISTANT)
|
||||||
char mqtt_ha_config[20 + sizeof(HOSTNAME) + 7]; // Topic config will be: "homeassistant/light/<HOSTNAME>/config"
|
char mqtt_ha_config[20 + sizeof(HOSTNAME) + 7]; // Topic config will be: "homeassistant/light/<HOSTNAME>/config"
|
||||||
char mqtt_ha_state_in[5 + sizeof(HOSTNAME) + 12]; // Topic in will be: "home/<HOSTNAME>_ha/state/in"
|
char mqtt_ha_state_in[5 + sizeof(HOSTNAME) + 12]; // Topic in will be: "home/<HOSTNAME>_ha/state/in"
|
||||||
char mqtt_ha_state_out[5 + sizeof(HOSTNAME) + 13]; // Topic in will be: "home/<HOSTNAME>_ha/state/out"
|
char mqtt_ha_state_out[5 + sizeof(HOSTNAME) + 13]; // Topic in will be: "home/<HOSTNAME>_ha/state/out"
|
||||||
const char* on_cmd = "ON";
|
const char* on_cmd = "ON";
|
||||||
const char* off_cmd = "OFF";
|
const char* off_cmd = "OFF";
|
||||||
bool new_ha_mqtt_msg = false;
|
bool new_ha_mqtt_msg = false;
|
||||||
uint16_t color_temp = 327; // min is 154 and max is 500
|
uint16_t color_temp = 327; // min is 154 and max is 500
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char mqtt_clientid[sizeof(HOSTNAME) + 9];
|
char mqtt_clientid[sizeof(HOSTNAME) + 9];
|
||||||
char mqtt_host[65] = ""; //is configurable just for the start
|
char mqtt_host[65] = ""; //is configurable just for the start
|
||||||
uint16_t mqtt_port = 1883; //is configurable just for the start
|
uint16_t mqtt_port = 1883; //is configurable just for the start
|
||||||
char mqtt_user[33] = ""; //is configurable just for the start
|
char mqtt_user[33] = ""; //is configurable just for the start
|
||||||
char mqtt_pass[33] = ""; //is configurable just for the start
|
char mqtt_pass[33] = ""; //is configurable just for the start
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// ***************************************************************************
|
// ***************************************************************************
|
||||||
// Global variables / definitions
|
// Global variables / definitions
|
||||||
// ***************************************************************************
|
// ***************************************************************************
|
||||||
#define DBG_OUTPUT_PORT Serial // Set debug output port
|
#define DBG_OUTPUT_PORT Serial // Set debug output port
|
||||||
|
|
||||||
uint8_t autoCount[10] = {}; // Global variable for storing the counter for automated playback for each segment
|
uint8_t autoCount[10] = {}; // Global variable for storing the counter for automated playback for each segment
|
||||||
unsigned long autoDelay[10] = {}; // Global variable for storing the time to next auto effect for each segment
|
unsigned long autoDelay[10] = {}; // Global variable for storing the time to next auto effect for each segment
|
||||||
struct {
|
struct {
|
||||||
uint16_t start = 0;
|
uint16_t start = 0;
|
||||||
uint16_t stop = NUMLEDS - 1;
|
uint16_t stop = NUMLEDS - 1;
|
||||||
uint8_t mode[10] = {}; // Global variable for storing the WS2812FX mode to set for each segment
|
uint8_t mode[10] = {}; // Global variable for storing the WS2812FX mode to set for each segment
|
||||||
uint8_t speed[10] = {}; // Global variable for storing the speed for effects --> smaller == slower
|
uint8_t speed[10] = {}; // Global variable for storing the speed for effects --> smaller == slower
|
||||||
uint32_t colors[10][3] = {}; // 2 dim. Color array for setting colors of WS2812FX
|
uint32_t colors[10][3] = {}; // 2 dim. Color array for setting colors of WS2812FX
|
||||||
uint8_t options = FX_OPTIONS;
|
uint8_t options = FX_OPTIONS;
|
||||||
} segState;
|
} segState;
|
||||||
|
|
||||||
// List of all color modes
|
// List of all color modes
|
||||||
enum MODE {OFF, HOLD, SET};
|
enum MODE {OFF, HOLD, SET};
|
||||||
MODE prevmode = HOLD; // Do not change
|
MODE prevmode = HOLD; // Do not change
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint8_t segment = 0; // Actual selected segment
|
uint8_t segment = 0; // Actual selected segment
|
||||||
MODE mode = SET; // Standard mode that is active when software starts
|
MODE mode = SET; // Standard mode that is active when software starts
|
||||||
uint8_t brightness = 196; // Global variable for storing the brightness (255 == 100%)
|
uint8_t brightness = 196; // Global variable for storing the brightness (255 == 100%)
|
||||||
} State;
|
} State;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint8_t segments = 1;
|
uint8_t segments = 1;
|
||||||
uint16_t stripSize = NUMLEDS;
|
uint16_t stripSize = NUMLEDS;
|
||||||
char RGBOrder[5] = RGBORDER;
|
char RGBOrder[5] = RGBORDER;
|
||||||
#if defined(USE_WS2812FX_DMA)
|
#if defined(USE_WS2812FX_DMA)
|
||||||
#if USE_WS2812FX_DMA == 0
|
#if USE_WS2812FX_DMA == 0
|
||||||
uint8_t pin = 3;
|
uint8_t pin = 3;
|
||||||
#endif
|
#endif
|
||||||
#if USE_WS2812FX_DMA == 1
|
#if USE_WS2812FX_DMA == 1
|
||||||
uint8_t pin = 2;
|
uint8_t pin = 1;
|
||||||
#endif
|
#endif
|
||||||
#if USE_WS2812FX_DMA == 2
|
#if USE_WS2812FX_DMA == 2
|
||||||
uint8_t pin = 1;
|
uint8_t pin = 2;
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
uint8_t pin = LED_PIN;
|
uint8_t pin = LED_PIN;
|
||||||
#endif
|
#endif
|
||||||
bool transEffect = false;
|
bool transEffect = false;
|
||||||
} Config;
|
} Config;
|
||||||
|
|
||||||
uint8_t fx_speed = 196; // Global variable for storing the speed for effects while fading --> smaller == slower
|
uint8_t fx_speed = 196; // Global variable for storing the speed for effects while fading --> smaller == slower
|
||||||
uint8_t fx_mode = 0;
|
uint8_t fx_mode = 0;
|
||||||
uint8_t brightness_trans = 0; // Global variable for storing the brightness before change
|
uint8_t brightness_trans = 0; // Global variable for storing the brightness before change
|
||||||
uint32_t hexcolors_trans[3] = {}; // Color array of colors of WS2812FX before fading
|
uint32_t hexcolors_trans[3] = {}; // Color array of colors of WS2812FX before fading
|
||||||
struct ledstate // Data structure to store a state of a single led
|
struct ledstate // Data structure to store a state of a single led
|
||||||
{
|
{
|
||||||
uint8_t red;
|
uint8_t red;
|
||||||
uint8_t green;
|
uint8_t green;
|
||||||
uint8_t blue;
|
uint8_t blue;
|
||||||
uint8_t white;
|
uint8_t white;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct ledstate LEDState; // Define the datatype LEDState
|
typedef struct ledstate LEDState; // Define the datatype LEDState
|
||||||
uint8_t* ledstates; // Set a pointer to get an array of led states to store the state of the whole strip
|
uint8_t* ledstates; // Set a pointer to get an array of led states to store the state of the whole strip
|
||||||
LEDState main_color = { 255, 0, 0, 0 }; // Store the "main color" of the strip used in single color modes
|
LEDState main_color = { 255, 0, 0, 0 }; // Store the "main color" of the strip used in single color modes
|
||||||
LEDState back_color = { 0, 0, 0, 0 }; // Store the "2nd color" of the strip used in single color modes
|
LEDState back_color = { 0, 0, 0, 0 }; // Store the "2nd color" of the strip used in single color modes
|
||||||
LEDState xtra_color = { 0, 0, 0, 0 }; // Store the "3rd color" of the strip used in single color modes
|
LEDState xtra_color = { 0, 0, 0, 0 }; // Store the "3rd color" of the strip used in single color modes
|
||||||
|
|
||||||
bool updateConfig = false; // For WiFiManger custom config and config
|
bool updateConfig = false; // For WiFiManger custom config and config
|
||||||
|
|
||||||
// Button handling
|
// Button handling
|
||||||
|
|
||||||
#if defined(ENABLE_BUTTON) || defined(ENABLE_BUTTON_GY33)
|
#if defined(ENABLE_BUTTON) || defined(ENABLE_BUTTON_GY33)
|
||||||
const unsigned long keySampleIntervalMs = 25;
|
const unsigned long keySampleIntervalMs = 25;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ENABLE_BUTTON)
|
#if defined(ENABLE_BUTTON)
|
||||||
//#define BTN_MODE_SHORT "STA|mo|fxm| s| b| r1| g1| b1| w1| r2| g2| b2| w2| r3| g3| b3| w3" // Example
|
//#define BTN_MODE_SHORT "STA|mo|fxm| s| b| r1| g1| b1| w1| r2| g2| b2| w2| r3| g3| b3| w3" // Example
|
||||||
#define BTN_MODE_SHORT "STA| 5| 0|196|255| 0| 0| 0|255| 0| 0| 0| 0| 0| 0| 0| 0" // Static white
|
#define BTN_MODE_SHORT "STA| 5| 0|196|255| 0| 0| 0|255| 0| 0| 0| 0| 0| 0| 0| 0" // Static white
|
||||||
#define BTN_MODE_MEDIUM "STA| 5| 48|196|200|255|102| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0" // Fire flicker
|
#define BTN_MODE_MEDIUM "STA| 5| 48|196|200|255|102| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0" // Fire flicker
|
||||||
#define BTN_MODE_LONG "STA| 5| 46|196|200|255|102| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0" // Fireworks random
|
#define BTN_MODE_LONG "STA| 5| 46|196|200|255|102| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0" // Fireworks random
|
||||||
unsigned long keyPrevMillis = 0;
|
unsigned long keyPrevMillis = 0;
|
||||||
byte longKeyPressCountMax = 80; // 80 * 25 = 2000 ms
|
byte longKeyPressCountMax = 80; // 80 * 25 = 2000 ms
|
||||||
byte mediumKeyPressCountMin = 20; // 20 * 25 = 500 ms
|
byte mediumKeyPressCountMin = 20; // 20 * 25 = 500 ms
|
||||||
byte KeyPressCount = 0;
|
byte KeyPressCount = 0;
|
||||||
byte prevKeyState = HIGH; // button is active low
|
byte prevKeyState = HIGH; // button is active low
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ENABLE_BUTTON_GY33)
|
#if defined(ENABLE_BUTTON_GY33)
|
||||||
unsigned long keyPrevMillis_gy33 = 0;
|
unsigned long keyPrevMillis_gy33 = 0;
|
||||||
byte longKeyPressCountMax_gy33 = 80; // 80 * 25 = 2000 ms
|
byte longKeyPressCountMax_gy33 = 80; // 80 * 25 = 2000 ms
|
||||||
byte mediumKeyPressCountMin_gy33 = 20; // 20 * 25 = 500 ms
|
byte mediumKeyPressCountMin_gy33 = 20; // 20 * 25 = 500 ms
|
||||||
byte KeyPressCount_gy33 = 0;
|
byte KeyPressCount_gy33 = 0;
|
||||||
byte prevKeyState_gy33 = HIGH; // button is active low
|
byte prevKeyState_gy33 = HIGH; // button is active low
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
// ***************************************************************************
|
|
||||||
// TV mode
|
|
||||||
// ***************************************************************************
|
|
||||||
|
|
||||||
uint8_t dipInterval = 10;
|
|
||||||
uint16_t darkTime = 250;
|
|
||||||
unsigned long currentDipTime;
|
|
||||||
unsigned long dipStartTime;
|
|
||||||
unsigned long currentMillis;
|
|
||||||
uint8_t ledState = LOW;
|
|
||||||
long previousMillis = 0;
|
|
||||||
uint16_t led = 5;
|
|
||||||
uint16_t interv = 2000;
|
|
||||||
uint8_t twitch = 50;
|
|
||||||
uint8_t dipCount = 0;
|
|
||||||
uint8_t analogLevel = 100;
|
|
||||||
boolean timeToDip = false;
|
|
||||||
|
|
||||||
|
|
||||||
void hsb2rgbAN1(uint16_t index, uint8_t sat, uint8_t bright, uint8_t myled) {
|
|
||||||
// Source: https://blog.adafruit.com/2012/03/14/constant-brightness-hsb-to-rgb-algorithm/
|
|
||||||
uint8_t temp[5], n = (index >> 8) % 3;
|
|
||||||
temp[0] = temp[3] = (uint8_t)(( (sat ^ 255) * bright) / 255);
|
|
||||||
temp[1] = temp[4] = (uint8_t)((((( (index & 255) * sat) / 255) + (sat ^ 255)) * bright) / 255);
|
|
||||||
temp[2] = (uint8_t)(((((((index & 255) ^ 255) * sat) / 255) + (sat ^ 255)) * bright) / 255);
|
|
||||||
strip->setPixelColor(myled, temp[n + 2], temp[n + 1], temp[n], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void updateLed (uint16_t led, uint8_t brightness) {
|
|
||||||
ledstates[led] = brightness;
|
|
||||||
for (uint16_t i=0; i<WS2812FXStripSettings.stripSize; i++) {
|
|
||||||
uint16_t index = (i%3 == 0) ? 400 : random(0,767);
|
|
||||||
hsb2rgbAN1(index, 200, ledstates[i], i);
|
|
||||||
}
|
|
||||||
strip->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// See: http://forum.mysensors.org/topic/85/phoneytv-for-vera-is-here/13
|
|
||||||
void handleTV() {
|
|
||||||
if (timeToDip == false) {
|
|
||||||
currentMillis = millis();
|
|
||||||
if(currentMillis-previousMillis > interv) {
|
|
||||||
previousMillis = currentMillis;
|
|
||||||
//interv = random(750,4001);//Adjusts the interval for more/less frequent random light changes
|
|
||||||
interv = random(1000-(ws2812fx_speed*2),5001-(ws2812fx_speed*8));
|
|
||||||
twitch = random(40,100);// Twitch provides motion effect but can be a bit much if too high
|
|
||||||
dipCount = dipCount++;
|
|
||||||
}
|
|
||||||
if(currentMillis-previousMillis<twitch) {
|
|
||||||
led=random(0, WS2812FXStripSettings.stripSize - 1);
|
|
||||||
analogLevel=random(50,255);// set the range of the 3 pwm leds
|
|
||||||
ledState = ledState == LOW ? HIGH: LOW; // if the LED is off turn it on and vice-versa:
|
|
||||||
updateLed(led, (ledState) ? 255 : 0);
|
|
||||||
if (dipCount > dipInterval) {
|
|
||||||
DBG_OUTPUT_PORT.println("dip");
|
|
||||||
timeToDip = true;
|
|
||||||
dipCount = 0;
|
|
||||||
dipStartTime = millis();
|
|
||||||
darkTime = random(50,150);
|
|
||||||
dipInterval = random(5,250);// cycles of flicker
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DBG_OUTPUT_PORT.println("Dip Time");
|
|
||||||
currentDipTime = millis();
|
|
||||||
if (currentDipTime - dipStartTime < darkTime) {
|
|
||||||
for (uint16_t i=3; i<WS2812FXStripSettings.stripSize; i++) {
|
|
||||||
updateLed(i, 0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
timeToDip = false;
|
|
||||||
}
|
|
||||||
//strip->show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -743,11 +743,15 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght
|
|||||||
root["effect"] = strip->getModeName(strip->getMode());
|
root["effect"] = strip->getModeName(strip->getMode());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
char buffer[measureJson(root) + 1];
|
uint16_t msg_len = measureJson(root) + 1;
|
||||||
|
char buffer[msg_len];
|
||||||
serializeJson(root, buffer, sizeof(buffer));
|
serializeJson(root, buffer, sizeof(buffer));
|
||||||
jsonBuffer.clear();
|
jsonBuffer.clear();
|
||||||
#if ENABLE_MQTT == 0
|
#if ENABLE_MQTT == 0
|
||||||
mqtt_client->publish(mqtt_ha_state_out, buffer, true);
|
//mqtt_client->publish(mqtt_ha_state_out, buffer, true);
|
||||||
|
mqtt_client->beginPublish(mqtt_ha_state_out, msg_len-1, true);
|
||||||
|
mqtt_client->write((const uint8_t*)buffer, msg_len-1);
|
||||||
|
mqtt_client->endPublish();
|
||||||
DBG_OUTPUT_PORT.printf("MQTT: Send [%s]: %s\r\n", mqtt_ha_state_out, buffer);
|
DBG_OUTPUT_PORT.printf("MQTT: Send [%s]: %s\r\n", mqtt_ha_state_out, buffer);
|
||||||
#endif
|
#endif
|
||||||
#if ENABLE_MQTT == 1
|
#if ENABLE_MQTT == 1
|
||||||
@@ -901,7 +905,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(ha_send_data.active()) ha_send_data.detach();
|
if(ha_send_data.active()) ha_send_data.detach();
|
||||||
ha_send_data.once(5, tickerSendState);
|
ha_send_data.once(DELAY_MQTT_HA_MESSAGE, tickerSendState);
|
||||||
} else if (strcmp(topic, mqtt_intopic) == 0) {
|
} else if (strcmp(topic, mqtt_intopic) == 0) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -936,7 +940,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght
|
|||||||
#if defined(ENABLE_HOMEASSISTANT)
|
#if defined(ENABLE_HOMEASSISTANT)
|
||||||
ha_send_data.detach();
|
ha_send_data.detach();
|
||||||
mqtt_client->subscribe(mqtt_ha_state_in, qossub);
|
mqtt_client->subscribe(mqtt_ha_state_in, qossub);
|
||||||
ha_send_data.once(5, tickerSendState);
|
ha_send_data.once(DELAY_MQTT_HA_MESSAGE, tickerSendState);
|
||||||
#if defined(MQTT_HOME_ASSISTANT_SUPPORT)
|
#if defined(MQTT_HOME_ASSISTANT_SUPPORT)
|
||||||
const size_t bufferSize = JSON_ARRAY_SIZE(strip->getModeCount()+ 4) + JSON_OBJECT_SIZE(11) + 1500;
|
const size_t bufferSize = JSON_ARRAY_SIZE(strip->getModeCount()+ 4) + JSON_OBJECT_SIZE(11) + 1500;
|
||||||
DynamicJsonDocument jsonBuffer(bufferSize);
|
DynamicJsonDocument jsonBuffer(bufferSize);
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define SKETCH_VERSION "3.1.0"
|
#define SKETCH_VERSION "3.1.1"
|
||||||
@@ -257,4 +257,8 @@
|
|||||||
* Version Bump to 3.1.0
|
* Version Bump to 3.1.0
|
||||||
* bugfixes
|
* bugfixes
|
||||||
* E1.31 is now working for multi segments
|
* E1.31 is now working for multi segments
|
||||||
*/
|
*
|
||||||
|
* 18 April 2020
|
||||||
|
* Version Bump to 3.1.1
|
||||||
|
* bugfixes regarding issue #80
|
||||||
|
*/
|
||||||
@@ -1,674 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<title>SPIFFS Editor</title>
|
|
||||||
<style type="text/css" media="screen">
|
|
||||||
.contextMenu {
|
|
||||||
z-index: 300;
|
|
||||||
position: absolute;
|
|
||||||
left: 5px;
|
|
||||||
border: 1px solid #444;
|
|
||||||
background-color: #F5F5F5;
|
|
||||||
display: none;
|
|
||||||
box-shadow: 0 0 10px rgba( 0, 0, 0, .4 );
|
|
||||||
font-size: 12px;
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.contextMenu ul {
|
|
||||||
list-style: none;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
.contextMenu li {
|
|
||||||
position: relative;
|
|
||||||
min-width: 60px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.contextMenu span {
|
|
||||||
color: #444;
|
|
||||||
display: inline-block;
|
|
||||||
padding: 6px;
|
|
||||||
}
|
|
||||||
.contextMenu li:hover { background: #444; }
|
|
||||||
.contextMenu li:hover span { color: #EEE; }
|
|
||||||
|
|
||||||
.css-treeview ul, .css-treeview li {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.css-treeview input {
|
|
||||||
position: absolute;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.css-treeview {
|
|
||||||
font: normal 11px Verdana, Arial, Sans-serif;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.css-treeview span {
|
|
||||||
color: #00f;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.css-treeview span:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.css-treeview input + label + ul {
|
|
||||||
margin: 0 0 0 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.css-treeview input ~ ul {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.css-treeview label, .css-treeview label::before {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.css-treeview input:disabled + label {
|
|
||||||
cursor: default;
|
|
||||||
opacity: .6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.css-treeview input:checked:not(:disabled) ~ ul {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.css-treeview label, .css-treeview label::before {
|
|
||||||
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAACgCAYAAAAFOewUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAApxJREFUeNrslM1u00AQgGdthyalFFOK+ClIIKQKyqUVQvTEE3DmAhLwAhU8QZoH4A2Q2gMSFace4MCtJ8SPBFwAkRuiHKpA6sRN/Lu7zG5i14kctaUqRGhGXnu9O/Pt7MzsMiklvF+9t2kWTDvyIrAsA0aKRRi1T0C/hJ4LUbt5/8rNpWVlp8RSr9J40b48fxFaTQ9+ft8EZ6MJYb0Ok+dnYGpmPgXwKIAvLx8vYXc5GdMAQJgQEkpjRTh36TS2U+DWW/D17WuYgm8pwJyY1npZsZKOxImOV1I/h4+O6vEg5GCZBpgmA6hX8wHKUHDRBXQYicQ4rlc3Tf0VMs8DHBS864F2YFspjgUYjKX/Az3gsdQd2eeBHwmdGWXHcgBGSkZXOXohcEXebRoQcAgjqediNY+AVyu3Z3sAKqfKoGMsewBeEIOPgQxxPJIjcGH6qtL/0AdADzKGnuuD+2tLK7Q8DhHHbOBW+KEzcHLuYc82MkEUekLiwuvVH+guQBQzOG4XdAb8EOcRcqQvDkY2iCLuxECJ43JobMXoutqGgDa2T7UqLKwt9KRyuxKVByqVXXqIoCCUCAqhUOioTWC7G4TQEOD0APy2/7G2Xpu1J4+lxeQ4TXBbITDpoVelRN/BVFbwu5oMMJUBhoXy5tmdRcMwymP2OLQaLjx9/vnBo6V3K6izATmSnMa0Dq7ferIohJhr1p01zrlz49rZF4OMs8JkX23vVQzYp+wbYGV/KpXKjvspl8tsIKCrMNAYFxj2GKS5ZWxg4ewKsJfaGMIY5KXqPz8LBBj6+yDvVP79+yDp/9F9oIx3OisHWwe7Oal0HxCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgwD8E/BZgAP0qhKj3rXO7AAAAAElFTkSuQmCC") no-repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
.css-treeview label, .css-treeview span, .css-treeview label::before {
|
|
||||||
display: inline-block;
|
|
||||||
height: 16px;
|
|
||||||
line-height: 16px;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.css-treeview label {
|
|
||||||
background-position: 18px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.css-treeview label::before {
|
|
||||||
content: "";
|
|
||||||
width: 16px;
|
|
||||||
margin: 0 22px 0 0;
|
|
||||||
vertical-align: middle;
|
|
||||||
background-position: 0 -32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.css-treeview input:checked + label::before {
|
|
||||||
background-position: 0 -16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* webkit adjacent element selector bugfix */
|
|
||||||
@media screen and (-webkit-min-device-pixel-ratio:0)
|
|
||||||
{
|
|
||||||
.css-treeview{
|
|
||||||
-webkit-animation: webkit-adjacent-element-selector-bugfix infinite 1s;
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes webkit-adjacent-element-selector-bugfix
|
|
||||||
{
|
|
||||||
from {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#uploader {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
left: 0;
|
|
||||||
height:28px;
|
|
||||||
line-height: 24px;
|
|
||||||
padding-left: 10px;
|
|
||||||
background-color: #444;
|
|
||||||
color:#EEE;
|
|
||||||
}
|
|
||||||
#tree {
|
|
||||||
position: absolute;
|
|
||||||
top: 28px;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
width:200px;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
#editor, #preview {
|
|
||||||
position: absolute;
|
|
||||||
top: 28px;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 200px;
|
|
||||||
}
|
|
||||||
#preview {
|
|
||||||
background-color: #EEE;
|
|
||||||
padding:5px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
function createFileUploader(element, tree, editor){
|
|
||||||
var xmlHttp;
|
|
||||||
var input = document.createElement("input");
|
|
||||||
input.type = "file";
|
|
||||||
input.multiple = false;
|
|
||||||
input.name = "data";
|
|
||||||
document.getElementById(element).appendChild(input);
|
|
||||||
var path = document.createElement("input");
|
|
||||||
path.id = "upload-path";
|
|
||||||
path.type = "text";
|
|
||||||
path.name = "path";
|
|
||||||
path.defaultValue = "/";
|
|
||||||
document.getElementById(element).appendChild(path);
|
|
||||||
var button = document.createElement("button");
|
|
||||||
button.innerHTML = 'Upload';
|
|
||||||
document.getElementById(element).appendChild(button);
|
|
||||||
var mkdir = document.createElement("button");
|
|
||||||
mkdir.innerHTML = 'MkDir';
|
|
||||||
document.getElementById(element).appendChild(mkdir);
|
|
||||||
var mkfile = document.createElement("button");
|
|
||||||
mkfile.innerHTML = 'MkFile';
|
|
||||||
document.getElementById(element).appendChild(mkfile);
|
|
||||||
|
|
||||||
function httpPostProcessRequest(){
|
|
||||||
if (xmlHttp.readyState == 4){
|
|
||||||
if(xmlHttp.status != 200) alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
|
|
||||||
else {
|
|
||||||
tree.refreshPath(path.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function createPath(p){
|
|
||||||
xmlHttp = new XMLHttpRequest();
|
|
||||||
xmlHttp.onreadystatechange = httpPostProcessRequest;
|
|
||||||
var formData = new FormData();
|
|
||||||
formData.append("path", p);
|
|
||||||
xmlHttp.open("PUT", "/edit");
|
|
||||||
xmlHttp.send(formData);
|
|
||||||
}
|
|
||||||
|
|
||||||
mkfile.onclick = function(e){
|
|
||||||
if(path.value.indexOf(".") === -1) return;
|
|
||||||
createPath(path.value);
|
|
||||||
editor.loadUrl(path.value);
|
|
||||||
};
|
|
||||||
mkdir.onclick = function(e){
|
|
||||||
if(path.value.length < 2) return;
|
|
||||||
var dir = path.value
|
|
||||||
if(dir.indexOf(".") !== -1){
|
|
||||||
if(dir.lastIndexOf("/") === 0) return;
|
|
||||||
dir = dir.substring(0, dir.lastIndexOf("/"));
|
|
||||||
}
|
|
||||||
createPath(dir);
|
|
||||||
};
|
|
||||||
button.onclick = function(e){
|
|
||||||
if(input.files.length === 0){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
xmlHttp = new XMLHttpRequest();
|
|
||||||
xmlHttp.onreadystatechange = httpPostProcessRequest;
|
|
||||||
var formData = new FormData();
|
|
||||||
formData.append("data", input.files[0], path.value);
|
|
||||||
xmlHttp.open("POST", "/edit");
|
|
||||||
xmlHttp.send(formData);
|
|
||||||
}
|
|
||||||
input.onchange = function(e){
|
|
||||||
if(input.files.length === 0) return;
|
|
||||||
var filename = input.files[0].name;
|
|
||||||
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
|
|
||||||
var name = /(.*)\.[^.]+$/.exec(filename)[1];
|
|
||||||
if(typeof name !== undefined){
|
|
||||||
if(name.length > 8) name = name.substring(0, 8);
|
|
||||||
filename = name;
|
|
||||||
}
|
|
||||||
if(typeof ext !== undefined){
|
|
||||||
if(ext === "html") ext = "htm";
|
|
||||||
else if(ext === "jpeg") ext = "jpg";
|
|
||||||
filename = filename + "." + ext;
|
|
||||||
}
|
|
||||||
if(path.value === "/" || path.value.lastIndexOf("/") === 0){
|
|
||||||
path.value = "/"+filename;
|
|
||||||
} else {
|
|
||||||
path.value = path.value.substring(0, path.value.lastIndexOf("/")+1)+filename;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createTree(element, editor){
|
|
||||||
var preview = document.getElementById("preview");
|
|
||||||
var treeRoot = document.createElement("div");
|
|
||||||
treeRoot.className = "css-treeview";
|
|
||||||
document.getElementById(element).appendChild(treeRoot);
|
|
||||||
|
|
||||||
function loadDownload(path){
|
|
||||||
document.getElementById('download-frame').src = path+"?download=true";
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadPreview(path){
|
|
||||||
document.getElementById("editor").style.display = "none";
|
|
||||||
preview.style.display = "block";
|
|
||||||
preview.innerHTML = '<img src="'+path+'" style="max-width:100%; max-height:100%; margin:auto; display:block;" />';
|
|
||||||
}
|
|
||||||
|
|
||||||
function fillFolderMenu(el, path){
|
|
||||||
var list = document.createElement("ul");
|
|
||||||
el.appendChild(list);
|
|
||||||
var action = document.createElement("li");
|
|
||||||
list.appendChild(action);
|
|
||||||
var isChecked = document.getElementById(path).checked;
|
|
||||||
var expnd = document.createElement("li");
|
|
||||||
list.appendChild(expnd);
|
|
||||||
if(isChecked){
|
|
||||||
expnd.innerHTML = "<span>Collapse</span>";
|
|
||||||
expnd.onclick = function(e){
|
|
||||||
document.getElementById(path).checked = false;
|
|
||||||
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
|
||||||
};
|
|
||||||
var refrsh = document.createElement("li");
|
|
||||||
list.appendChild(refrsh);
|
|
||||||
refrsh.innerHTML = "<span>Refresh</span>";
|
|
||||||
refrsh.onclick = function(e){
|
|
||||||
var leaf = document.getElementById(path).parentNode;
|
|
||||||
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
|
|
||||||
httpGet(leaf, path);
|
|
||||||
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
expnd.innerHTML = "<span>Expand</span>";
|
|
||||||
expnd.onclick = function(e){
|
|
||||||
document.getElementById(path).checked = true;
|
|
||||||
var leaf = document.getElementById(path).parentNode;
|
|
||||||
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
|
|
||||||
httpGet(leaf, path);
|
|
||||||
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
var upload = document.createElement("li");
|
|
||||||
list.appendChild(upload);
|
|
||||||
upload.innerHTML = "<span>Upload</span>";
|
|
||||||
upload.onclick = function(e){
|
|
||||||
var pathEl = document.getElementById("upload-path");
|
|
||||||
if(pathEl){
|
|
||||||
var subPath = pathEl.value;
|
|
||||||
if(subPath.lastIndexOf("/") < 1) pathEl.value = path+subPath;
|
|
||||||
else pathEl.value = path.substring(subPath.lastIndexOf("/"))+subPath;
|
|
||||||
}
|
|
||||||
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
|
||||||
};
|
|
||||||
var delFile = document.createElement("li");
|
|
||||||
list.appendChild(delFile);
|
|
||||||
delFile.innerHTML = "<span>Delete</span>";
|
|
||||||
delFile.onclick = function(e){
|
|
||||||
httpDelete(path);
|
|
||||||
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function fillFileMenu(el, path){
|
|
||||||
var list = document.createElement("ul");
|
|
||||||
el.appendChild(list);
|
|
||||||
var action = document.createElement("li");
|
|
||||||
list.appendChild(action);
|
|
||||||
if(isTextFile(path)){
|
|
||||||
action.innerHTML = "<span>Edit</span>";
|
|
||||||
action.onclick = function(e){
|
|
||||||
editor.loadUrl(path);
|
|
||||||
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
|
||||||
};
|
|
||||||
} else if(isImageFile(path)){
|
|
||||||
action.innerHTML = "<span>Preview</span>";
|
|
||||||
action.onclick = function(e){
|
|
||||||
loadPreview(path);
|
|
||||||
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
var download = document.createElement("li");
|
|
||||||
list.appendChild(download);
|
|
||||||
download.innerHTML = "<span>Download</span>";
|
|
||||||
download.onclick = function(e){
|
|
||||||
loadDownload(path);
|
|
||||||
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
|
||||||
};
|
|
||||||
var delFile = document.createElement("li");
|
|
||||||
list.appendChild(delFile);
|
|
||||||
delFile.innerHTML = "<span>Delete</span>";
|
|
||||||
delFile.onclick = function(e){
|
|
||||||
httpDelete(path);
|
|
||||||
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function showContextMenu(e, path, isfile){
|
|
||||||
var divContext = document.createElement("div");
|
|
||||||
var scrollTop = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;
|
|
||||||
var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft : document.documentElement.scrollLeft;
|
|
||||||
var left = e.clientX + scrollLeft;
|
|
||||||
var top = e.clientY + scrollTop;
|
|
||||||
divContext.className = 'contextMenu';
|
|
||||||
divContext.style.display = 'block';
|
|
||||||
divContext.style.left = left + 'px';
|
|
||||||
divContext.style.top = top + 'px';
|
|
||||||
if(isfile) fillFileMenu(divContext, path);
|
|
||||||
else fillFolderMenu(divContext, path);
|
|
||||||
document.body.appendChild(divContext);
|
|
||||||
var width = divContext.offsetWidth;
|
|
||||||
var height = divContext.offsetHeight;
|
|
||||||
divContext.onmouseout = function(e){
|
|
||||||
if(e.clientX < left || e.clientX > (left + width) || e.clientY < top || e.clientY > (top + height)){
|
|
||||||
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(divContext);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function createTreeLeaf(path, name, size){
|
|
||||||
var leaf = document.createElement("li");
|
|
||||||
leaf.id = (((path == "/")?"":path)+"/"+name).toLowerCase();
|
|
||||||
var label = document.createElement("span");
|
|
||||||
label.textContent = name.toLowerCase();
|
|
||||||
leaf.appendChild(label);
|
|
||||||
leaf.onclick = function(e){
|
|
||||||
if(isTextFile(leaf.id)){
|
|
||||||
editor.loadUrl(leaf.id);
|
|
||||||
} else if(isImageFile(leaf.id)){
|
|
||||||
loadPreview(leaf.id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
leaf.oncontextmenu = function(e){
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
showContextMenu(e, leaf.id, true);
|
|
||||||
};
|
|
||||||
return leaf;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createTreeBranch(path, name, disabled){
|
|
||||||
var leaf = document.createElement("li");
|
|
||||||
var check = document.createElement("input");
|
|
||||||
check.type = "checkbox";
|
|
||||||
check.id = (((path == "/")?"":path)+"/"+name).toLowerCase();
|
|
||||||
if(typeof disabled !== "undefined" && disabled) check.disabled = "disabled";
|
|
||||||
leaf.appendChild(check);
|
|
||||||
var label = document.createElement("label");
|
|
||||||
label.for = check.id;
|
|
||||||
label.textContent = name.toLowerCase();
|
|
||||||
leaf.appendChild(label);
|
|
||||||
check.onchange = function(e){
|
|
||||||
if(check.checked){
|
|
||||||
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
|
|
||||||
httpGet(leaf, check.id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
label.onclick = function(e){
|
|
||||||
if(!check.checked){
|
|
||||||
check.checked = true;
|
|
||||||
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
|
|
||||||
httpGet(leaf, check.id);
|
|
||||||
} else {
|
|
||||||
check.checked = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
leaf.oncontextmenu = function(e){
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
showContextMenu(e, check.id, false);
|
|
||||||
}
|
|
||||||
return leaf;
|
|
||||||
}
|
|
||||||
|
|
||||||
function addList(parent, path, items){
|
|
||||||
var list = document.createElement("ul");
|
|
||||||
parent.appendChild(list);
|
|
||||||
var ll = items.length;
|
|
||||||
for(var i = 0; i < ll; i++){
|
|
||||||
var item = items[i];
|
|
||||||
var itemEl;
|
|
||||||
if(item.type === "file"){
|
|
||||||
itemEl = createTreeLeaf(path, item.name, item.size);
|
|
||||||
} else {
|
|
||||||
itemEl = createTreeBranch(path, item.name);
|
|
||||||
}
|
|
||||||
list.appendChild(itemEl);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function isTextFile(path){
|
|
||||||
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
|
|
||||||
if(typeof ext !== undefined){
|
|
||||||
switch(ext){
|
|
||||||
case "txt":
|
|
||||||
case "htm":
|
|
||||||
case "html":
|
|
||||||
case "js":
|
|
||||||
case "json":
|
|
||||||
case "c":
|
|
||||||
case "h":
|
|
||||||
case "cpp":
|
|
||||||
case "css":
|
|
||||||
case "xml":
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isImageFile(path){
|
|
||||||
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
|
|
||||||
if(typeof ext !== undefined){
|
|
||||||
switch(ext){
|
|
||||||
case "png":
|
|
||||||
case "jpg":
|
|
||||||
case "gif":
|
|
||||||
case "ico":
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.refreshPath = function(path){
|
|
||||||
if(path.lastIndexOf('/') < 1){
|
|
||||||
path = '/';
|
|
||||||
treeRoot.removeChild(treeRoot.childNodes[0]);
|
|
||||||
httpGet(treeRoot, "/");
|
|
||||||
} else {
|
|
||||||
path = path.substring(0, path.lastIndexOf('/'));
|
|
||||||
var leaf = document.getElementById(path).parentNode;
|
|
||||||
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
|
|
||||||
httpGet(leaf, path);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function delCb(path){
|
|
||||||
return function(){
|
|
||||||
if (xmlHttp.readyState == 4){
|
|
||||||
if(xmlHttp.status != 200){
|
|
||||||
alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
|
|
||||||
} else {
|
|
||||||
if(path.lastIndexOf('/') < 1){
|
|
||||||
path = '/';
|
|
||||||
treeRoot.removeChild(treeRoot.childNodes[0]);
|
|
||||||
httpGet(treeRoot, "/");
|
|
||||||
} else {
|
|
||||||
path = path.substring(0, path.lastIndexOf('/'));
|
|
||||||
var leaf = document.getElementById(path).parentNode;
|
|
||||||
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
|
|
||||||
httpGet(leaf, path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function httpDelete(filename){
|
|
||||||
xmlHttp = new XMLHttpRequest();
|
|
||||||
xmlHttp.onreadystatechange = delCb(filename);
|
|
||||||
var formData = new FormData();
|
|
||||||
formData.append("path", filename);
|
|
||||||
xmlHttp.open("DELETE", "/edit");
|
|
||||||
xmlHttp.send(formData);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCb(parent, path){
|
|
||||||
return function(){
|
|
||||||
if (xmlHttp.readyState == 4){
|
|
||||||
//clear loading
|
|
||||||
if(xmlHttp.status == 200) addList(parent, path, JSON.parse(xmlHttp.responseText));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function httpGet(parent, path){
|
|
||||||
xmlHttp = new XMLHttpRequest(parent, path);
|
|
||||||
xmlHttp.onreadystatechange = getCb(parent, path);
|
|
||||||
xmlHttp.open("GET", "/list?dir="+path, true);
|
|
||||||
xmlHttp.send(null);
|
|
||||||
//start loading
|
|
||||||
}
|
|
||||||
|
|
||||||
httpGet(treeRoot, "/");
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createEditor(element, file, lang, theme, type){
|
|
||||||
function getLangFromFilename(filename){
|
|
||||||
var lang = "plain";
|
|
||||||
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
|
|
||||||
if(typeof ext !== undefined){
|
|
||||||
switch(ext){
|
|
||||||
case "txt": lang = "plain"; break;
|
|
||||||
case "htm": lang = "html"; break;
|
|
||||||
case "js": lang = "javascript"; break;
|
|
||||||
case "c": lang = "c_cpp"; break;
|
|
||||||
case "cpp": lang = "c_cpp"; break;
|
|
||||||
case "css":
|
|
||||||
case "scss":
|
|
||||||
case "php":
|
|
||||||
case "html":
|
|
||||||
case "json":
|
|
||||||
case "xml":
|
|
||||||
lang = ext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lang;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(typeof file === "undefined") file = "/index.htm";
|
|
||||||
|
|
||||||
if(typeof lang === "undefined"){
|
|
||||||
lang = getLangFromFilename(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(typeof theme === "undefined") theme = "textmate";
|
|
||||||
|
|
||||||
if(typeof type === "undefined"){
|
|
||||||
type = "text/"+lang;
|
|
||||||
if(lang === "c_cpp") type = "text/plain";
|
|
||||||
}
|
|
||||||
|
|
||||||
var xmlHttp = null;
|
|
||||||
var editor = ace.edit(element);
|
|
||||||
|
|
||||||
//post
|
|
||||||
function httpPostProcessRequest(){
|
|
||||||
if (xmlHttp.readyState == 4){
|
|
||||||
if(xmlHttp.status != 200) alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function httpPost(filename, data, type){
|
|
||||||
xmlHttp = new XMLHttpRequest();
|
|
||||||
xmlHttp.onreadystatechange = httpPostProcessRequest;
|
|
||||||
var formData = new FormData();
|
|
||||||
formData.append("data", new Blob([data], { type: type }), filename);
|
|
||||||
xmlHttp.open("POST", "/edit");
|
|
||||||
xmlHttp.send(formData);
|
|
||||||
}
|
|
||||||
//get
|
|
||||||
function httpGetProcessRequest(){
|
|
||||||
if (xmlHttp.readyState == 4){
|
|
||||||
document.getElementById("preview").style.display = "none";
|
|
||||||
document.getElementById("editor").style.display = "block";
|
|
||||||
if(xmlHttp.status == 200) editor.setValue(xmlHttp.responseText);
|
|
||||||
else editor.setValue("");
|
|
||||||
editor.clearSelection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function httpGet(theUrl){
|
|
||||||
xmlHttp = new XMLHttpRequest();
|
|
||||||
xmlHttp.onreadystatechange = httpGetProcessRequest;
|
|
||||||
xmlHttp.open("GET", theUrl, true);
|
|
||||||
xmlHttp.send(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(lang !== "plain") editor.getSession().setMode("ace/mode/"+lang);
|
|
||||||
editor.setTheme("ace/theme/"+theme);
|
|
||||||
editor.$blockScrolling = Infinity;
|
|
||||||
editor.getSession().setUseSoftTabs(true);
|
|
||||||
editor.getSession().setTabSize(2);
|
|
||||||
editor.setHighlightActiveLine(true);
|
|
||||||
editor.setShowPrintMargin(false);
|
|
||||||
editor.commands.addCommand({
|
|
||||||
name: 'saveCommand',
|
|
||||||
bindKey: {win: 'Ctrl-S', mac: 'Command-S'},
|
|
||||||
exec: function(editor) {
|
|
||||||
httpPost(file, editor.getValue()+"", type);
|
|
||||||
},
|
|
||||||
readOnly: false
|
|
||||||
});
|
|
||||||
editor.commands.addCommand({
|
|
||||||
name: 'undoCommand',
|
|
||||||
bindKey: {win: 'Ctrl-Z', mac: 'Command-Z'},
|
|
||||||
exec: function(editor) {
|
|
||||||
editor.getSession().getUndoManager().undo(false);
|
|
||||||
},
|
|
||||||
readOnly: false
|
|
||||||
});
|
|
||||||
editor.commands.addCommand({
|
|
||||||
name: 'redoCommand',
|
|
||||||
bindKey: {win: 'Ctrl-Shift-Z', mac: 'Command-Shift-Z'},
|
|
||||||
exec: function(editor) {
|
|
||||||
editor.getSession().getUndoManager().redo(false);
|
|
||||||
},
|
|
||||||
readOnly: false
|
|
||||||
});
|
|
||||||
httpGet(file);
|
|
||||||
editor.loadUrl = function(filename){
|
|
||||||
file = filename;
|
|
||||||
lang = getLangFromFilename(file);
|
|
||||||
type = "text/"+lang;
|
|
||||||
if(lang !== "plain") editor.getSession().setMode("ace/mode/"+lang);
|
|
||||||
httpGet(file);
|
|
||||||
}
|
|
||||||
return editor;
|
|
||||||
}
|
|
||||||
function onBodyLoad(){
|
|
||||||
var vars = {};
|
|
||||||
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) { vars[key] = value; });
|
|
||||||
var editor = createEditor("editor", vars.file, vars.lang, vars.theme);
|
|
||||||
var tree = createTree("tree", editor);
|
|
||||||
createFileUploader("uploader", tree, editor);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.9/ace.js" type="text/javascript" charset="utf-8"></script>
|
|
||||||
</head>
|
|
||||||
<body onload="onBodyLoad();">
|
|
||||||
<div id="uploader"></div>
|
|
||||||
<div id="tree"></div>
|
|
||||||
<div id="editor"></div>
|
|
||||||
<div id="preview" style="display:none;"></div>
|
|
||||||
<iframe id=download-frame style='display:none;'></iframe>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB |
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,4 +0,0 @@
|
|||||||
## Retired, use:
|
|
||||||
McLightingHTML from https://github.com/FabLab-Luenen/McLightingHTML
|
|
||||||
|
|
||||||
or set #define USE_HTML_MIN_GZ in definitions.h to use the integrated!
|
|
||||||
@@ -1,491 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!--Import Google Icon Font-->
|
|
||||||
<link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
||||||
<!--Import materialize.css-->
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.min.css" media="screen,projection" />
|
|
||||||
|
|
||||||
<!--Let browser know website is optimized for mobile-->
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
|
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
|
||||||
<title>McLighting (RGBW) v2</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<nav class="blue light-blueXXX lighten-1XXX" role="navigation" id="mc-nav">
|
|
||||||
<div class="nav-wrapper container">
|
|
||||||
<a id="logo-container" href="#" class="brand-logo">McLighting (RGBW) v2</a>
|
|
||||||
|
|
||||||
<ul class="right hide-on-med-and-down">
|
|
||||||
<li><a href="#" class="mc-navlink" data-pane="pane1">Wheel</a></li>
|
|
||||||
<li><a href="#" class="mc-navlink" data-pane="pane2">Modes</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul id="nav-mobile" class="side-nav">
|
|
||||||
<li><a href="#" class="mc-navlink" data-pane="pane1">Wheel</a></li>
|
|
||||||
<li><a href="#" class="mc-navlink" data-pane="pane2">Modes</a></li>
|
|
||||||
</ul>
|
|
||||||
<a href="#" data-activates="nav-mobile" class="button-collapse"><i class="material-icons">menu</i></a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="container mc_pane" id="pane0">
|
|
||||||
<div class="section">
|
|
||||||
<div class="row" id="mc-wsloader">
|
|
||||||
<div class="col">
|
|
||||||
<div class="preloader-wrapper active">
|
|
||||||
<div class="spinner-layer spinner-blue-only">
|
|
||||||
<div class="circle-clipper left">
|
|
||||||
<div class="circle"></div>
|
|
||||||
</div>
|
|
||||||
<div class="gap-patch">
|
|
||||||
<div class="circle"></div>
|
|
||||||
</div>
|
|
||||||
<div class="circle-clipper right">
|
|
||||||
<div class="circle"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row hide" id="mc-wserror">
|
|
||||||
<div class="col">
|
|
||||||
<div>Error on websocket connect.</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container mc_pane hide" id="pane1">
|
|
||||||
<div class="section">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col s12 m6">
|
|
||||||
<div style="height: 330px; width: 330px;">
|
|
||||||
<canvas id="myCanvas" width="330" height="330" style="-webkit-user-select: none;-webkit-tap-highlight-color: rgba(0,0,0,0);-moz-user-select:none;"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col s12 m6">
|
|
||||||
<div class="card-panel" id="status">
|
|
||||||
<div id="status_pos">pick a color</div>
|
|
||||||
<div id="status_color"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col s12 m6">
|
|
||||||
<div class="right switch">Auto:<br>
|
|
||||||
<label>Off
|
|
||||||
<input id="autoSwitch" type="checkbox"><span class="lever"></span>On
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container mc_pane hide" id="pane2">
|
|
||||||
<div class="section">
|
|
||||||
<div class="row">
|
|
||||||
<form class="col s12">
|
|
||||||
<div class="row">
|
|
||||||
<div class="input-field col s12 l4">
|
|
||||||
<label for="txt_red">Red</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_red" min="0" max="255" class="update_colors" /></p>
|
|
||||||
</div>
|
|
||||||
<div class="input-field col s12 l4">
|
|
||||||
<label for="txt_green">Green</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_green" min="0" max="255" class="update_colors" /></p>
|
|
||||||
</div>
|
|
||||||
<div class="input-field col s12 l4">
|
|
||||||
<label for="txt_blue">Blue</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_blue" min="0" max="255" class="update_colors" /></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="input-field col s12">
|
|
||||||
<label for="txt_white">White</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_white" min="0" max="255" class="update_colors" /></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="input-field col s12">
|
|
||||||
<label for="txt_delay">Speed</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_delay" min="0" max="255" value="196" class="update_delay" /></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="input-field col s12">
|
|
||||||
<label for="txt_delay">Brightness</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_brightness" min="0" max="255" value="196" class="update_brightness" /></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div id="modes">
|
|
||||||
<div class="input-field col s12">
|
|
||||||
Loading animations...
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer class="page-footer blue">
|
|
||||||
<div class="footer-copyright">
|
|
||||||
<div class="container">© 2017
|
|
||||||
<a class="grey-text text-lighten-4 right" href="https://github.com/toblum/McLighting">Project home</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<style type="text/css">
|
|
||||||
.btn_grid {
|
|
||||||
margin: 7px 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<!--Import jQuery before materialize.js-->
|
|
||||||
<script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
|
|
||||||
<script type="text/javascript">(function($){
|
|
||||||
$(function(){
|
|
||||||
|
|
||||||
// Settings
|
|
||||||
var host = window.location.hostname;
|
|
||||||
//host = "esp8266_02.local";
|
|
||||||
|
|
||||||
var ws_url = 'ws://' + host + ':81';
|
|
||||||
var connection;
|
|
||||||
var ws_waiting = 0;
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// Side navigation
|
|
||||||
// ******************************************************************
|
|
||||||
$('.button-collapse').sideNav();
|
|
||||||
|
|
||||||
// Navlinks
|
|
||||||
$('#mc-nav').on('click', '.mc-navlink', function(){
|
|
||||||
console.log("Navigate to pane: ", $(this).data("pane"));
|
|
||||||
showPane($(this).data("pane"));
|
|
||||||
});
|
|
||||||
|
|
||||||
function showPane(pane) {
|
|
||||||
$('.mc_pane').addClass('hide');
|
|
||||||
$('#' + pane).removeClass('hide');
|
|
||||||
$('.button-collapse').sideNav('hide');
|
|
||||||
|
|
||||||
//if (pane == "pane2") {
|
|
||||||
// setMainColor();
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// init()
|
|
||||||
// ******************************************************************
|
|
||||||
function init() {
|
|
||||||
console.log("Connection websockets to:", ws_url);
|
|
||||||
connection = new WebSocket(ws_url, ['arduino']);
|
|
||||||
var mode = 0;
|
|
||||||
var ws2812fx_mode = 0;
|
|
||||||
$.getJSON("http://" + host + "/status", function(data) {
|
|
||||||
console.log("status", data);
|
|
||||||
mode = data.mode;
|
|
||||||
if (mode == "1") {
|
|
||||||
// set autoswitch $("#autoSwitch").val('checked');
|
|
||||||
}
|
|
||||||
ws2812fx_mode = data.ws2812fx_mode;
|
|
||||||
$("#rng_delay").val(data.speed);
|
|
||||||
$("#rng_brightness").val(data.brightness);
|
|
||||||
$("#rng_white").val(data.color[0]);
|
|
||||||
$("#rng_red").val(data.color[1]);
|
|
||||||
$("#rng_green").val(data.color[2]);
|
|
||||||
$("#rng_blue").val(data.color[3]);
|
|
||||||
var statusColor = "#" + componentToHex(data.color[1]) + componentToHex(data.color[2]) + componentToHex(data.color[3]);
|
|
||||||
$('#status').css("backgroundColor", statusColor);
|
|
||||||
$('#status_color').text(statusColor + "- R=" + data.color[1] + ", G=" + data.color[2] + ", B=" + data.color[3]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Load modes async
|
|
||||||
// List of all color modes
|
|
||||||
// enum MODE {OFF, AUTO, TV, E131, SET_MODE, HOLD, CUSTOM, SETCOLOR, SETSPEED, BRIGHTNESS, WIPE, RAINBOW, RAINBOWCYCLE, THEATERCHASE, TWINKLERANDOM, THEATERCHASERAINBOW};
|
|
||||||
$.getJSON("http://" + host + "/get_modes", function(data) {
|
|
||||||
console.log("modes", data);
|
|
||||||
var modes_html = "";
|
|
||||||
data.forEach(function(current_mode){
|
|
||||||
if (current_mode.mode !== undefined) {
|
|
||||||
modes_html += '<div class="col s12 m6 l6 btn_grid">';
|
|
||||||
if ((mode == "5" && current_mode.mode == ws2812fx_mode) || (mode == "0" && current_mode.mode == "off") || (mode == "2" && current_mode.mode == "tv") || (mode == "3" && current_mode.mode == "e131")){
|
|
||||||
modes_html += '<a class="btn waves-effect waves-light btn_mode red" name="action" data-mode="' + current_mode.mode + '">(' + current_mode.mode +') '+ current_mode.name;
|
|
||||||
} else {
|
|
||||||
modes_html += '<a class="btn waves-effect waves-light btn_mode blue" name="action" data-mode="' + current_mode.mode + '">(' + current_mode.mode +') '+ current_mode.name;
|
|
||||||
}
|
|
||||||
modes_html += '<i class="material-icons right">send</i>';
|
|
||||||
modes_html += '</a>';
|
|
||||||
modes_html += '</div>';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#modes').html(modes_html);
|
|
||||||
});
|
|
||||||
// When the connection is open, send some data to the server
|
|
||||||
connection.onopen = function () {
|
|
||||||
//connection.send('Ping'); // Send the message 'Ping' to the server
|
|
||||||
console.log('WebSocket Open');
|
|
||||||
showPane('pane1');
|
|
||||||
};
|
|
||||||
|
|
||||||
// Log errors
|
|
||||||
connection.onerror = function (error) {
|
|
||||||
console.log('WebSocket Error ' + error);
|
|
||||||
$('#mc-wsloader').addClass('hide');
|
|
||||||
$('#mc-wserror').removeClass('hide');
|
|
||||||
};
|
|
||||||
|
|
||||||
// Log messages from the server
|
|
||||||
connection.onmessage = function (e) {
|
|
||||||
console.log('WebSocket from server: ' + e.data);
|
|
||||||
ws_waiting = 0;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// Modes
|
|
||||||
// ******************************************************************
|
|
||||||
$("#pane2").on("click", ".btn_mode", function() {
|
|
||||||
var mode = $(this).attr("data-mode");
|
|
||||||
last_mode = mode;
|
|
||||||
var btn = $(this);
|
|
||||||
setMode(mode, function() {
|
|
||||||
$(".btn_mode, .btn_mode_static").removeClass("red").addClass("blue");
|
|
||||||
btn.removeClass("blue").addClass("red");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#pane2").on("click", ".btn_mode_static", function() {
|
|
||||||
var mode = $(this).attr("data-mode");
|
|
||||||
var btn = $(this);
|
|
||||||
|
|
||||||
wsSendCommand("=" + mode);
|
|
||||||
$(".btn_mode, .btn_mode_static").removeClass("red").addClass("blue");
|
|
||||||
btn.removeClass("blue").addClass("red");
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#pane2").on("change", ".update_colors", setMainColor);
|
|
||||||
|
|
||||||
$("#pane2").on("change", ".update_delay", function() {
|
|
||||||
var delay = $("#rng_delay").val();
|
|
||||||
|
|
||||||
wsSendCommand("?" + delay);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#pane2").on("change", ".update_brightness", function() {
|
|
||||||
var brightness = $("#rng_brightness").val();
|
|
||||||
|
|
||||||
wsSendCommand("%" + brightness);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#autoSwitch").on("change", function () {
|
|
||||||
if ($(this).prop('checked')) {
|
|
||||||
wsSendCommand("start");
|
|
||||||
} else {
|
|
||||||
wsSendCommand("stop");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function setMode(mode, finish_funtion) {
|
|
||||||
console.log("Mode: ", mode);
|
|
||||||
|
|
||||||
wsSendCommand("/" + mode);
|
|
||||||
finish_funtion();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setMainColor() {
|
|
||||||
var white = $("#rng_white").val();
|
|
||||||
var red = $("#rng_red").val();
|
|
||||||
var green = $("#rng_green").val();
|
|
||||||
var blue = $("#rng_blue").val();
|
|
||||||
|
|
||||||
var hexColor = componentToHex(white) + componentToHex(red) + componentToHex(green) + componentToHex(blue);
|
|
||||||
var statusColor = "#" + componentToHex(red) + componentToHex(green) + componentToHex(blue);
|
|
||||||
wsSetMainColor(hexColor);
|
|
||||||
$('#status').css("backgroundColor", statusColor);
|
|
||||||
$('#status_color').text(statusColor + "- R=" + red + ", G=" + green + ", B=" + blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// WebSocket commands
|
|
||||||
// ******************************************************************
|
|
||||||
function wsSendCommand(cmd) {
|
|
||||||
console.log("Send WebSocket command:", cmd);
|
|
||||||
if (ws_waiting == 0) {
|
|
||||||
connection.send(cmd);
|
|
||||||
ws_waiting++;
|
|
||||||
} else {
|
|
||||||
console.log("++++++++ WS call waiting, skip")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function wsSetAll(hexColor) {
|
|
||||||
console.log("wsSetAll() Set all colors to:", hexColor);
|
|
||||||
wsSendCommand("*" + hexColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
function wsSetMainColor(hexColor) {
|
|
||||||
console.log("wsSetMainColor() Set main colors to:", hexColor);
|
|
||||||
wsSendCommand("#" + hexColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// Colorwheel
|
|
||||||
// ******************************************************************
|
|
||||||
// this is supposed to work on mobiles (touch) as well as on a desktop (click)
|
|
||||||
// since we couldn't find a decent one .. this try of writing one by myself
|
|
||||||
// + google. swiping would be really nice - I will possibly implement it with
|
|
||||||
// jquery later - or never.
|
|
||||||
|
|
||||||
var canvas = document.getElementById("myCanvas");
|
|
||||||
// FIX: Cancel touch end event and handle click via touchstart
|
|
||||||
// canvas.addEventListener("touchend", function(e) { e.preventDefault(); }, false);
|
|
||||||
canvas.addEventListener("touchmove", doTouch, false);
|
|
||||||
canvas.addEventListener("click", doClick, false);
|
|
||||||
//canvas.addEventListener("mousemove", doClick, false);
|
|
||||||
|
|
||||||
|
|
||||||
var context = canvas.getContext('2d');
|
|
||||||
var centerX = canvas.width / 2;
|
|
||||||
var centerY = canvas.height / 2;
|
|
||||||
var innerRadius = canvas.width / 4.5;
|
|
||||||
var outerRadius = (canvas.width - 10) / 2
|
|
||||||
|
|
||||||
//outer border
|
|
||||||
context.beginPath();
|
|
||||||
//outer circle
|
|
||||||
context.arc(centerX, centerY, outerRadius, 0, 2 * Math.PI, false);
|
|
||||||
//draw the outer border: (gets drawn around the circle!)
|
|
||||||
context.lineWidth = 4;
|
|
||||||
context.strokeStyle = '#000000';
|
|
||||||
context.stroke();
|
|
||||||
context.closePath();
|
|
||||||
|
|
||||||
//fill with beautiful colors
|
|
||||||
//taken from here: http://stackoverflow.com/questions/18265804/building-a-color-wheel-in-html5
|
|
||||||
for(var angle=0; angle<=360; angle+=1) {
|
|
||||||
var startAngle = (angle-2)*Math.PI/180;
|
|
||||||
var endAngle = angle * Math.PI/180;
|
|
||||||
context.beginPath();
|
|
||||||
context.moveTo(centerX, centerY);
|
|
||||||
context.arc(centerX, centerY, outerRadius, startAngle, endAngle, false);
|
|
||||||
context.closePath();
|
|
||||||
context.fillStyle = 'hsl('+angle+', 100%, 50%)';
|
|
||||||
context.fill();
|
|
||||||
context.closePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
//inner border
|
|
||||||
context.beginPath();
|
|
||||||
//context.arc(centerX, centerY, radius, startAngle, endAngle, counterClockwise);
|
|
||||||
context.arc(centerX, centerY, innerRadius, 0, 2 * Math.PI, false);
|
|
||||||
//fill the center
|
|
||||||
var my_gradient=context.createLinearGradient(0,0,170,0);
|
|
||||||
my_gradient.addColorStop(0,"black");
|
|
||||||
my_gradient.addColorStop(1,"white");
|
|
||||||
|
|
||||||
context.fillStyle = my_gradient;
|
|
||||||
context.fillStyle = "white";
|
|
||||||
context.fill();
|
|
||||||
|
|
||||||
//draw the inner line
|
|
||||||
context.lineWidth = 2;
|
|
||||||
context.strokeStyle = '#000000';
|
|
||||||
context.stroke();
|
|
||||||
context.closePath();
|
|
||||||
|
|
||||||
//get Mouse x/y canvas position
|
|
||||||
function getMousePos(canvas, evt) {
|
|
||||||
var rect = canvas.getBoundingClientRect();
|
|
||||||
return {
|
|
||||||
x: evt.clientX - rect.left,
|
|
||||||
y: evt.clientY - rect.top
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//comp to Hex
|
|
||||||
function componentToHex(c) {
|
|
||||||
//var hex = c.toString(16);
|
|
||||||
//return hex.length == 1 ? "0" + hex : hex;
|
|
||||||
return ("0"+(Number(c).toString(16))).slice(-2).toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
//rgb/rgba to Hex
|
|
||||||
function rgbToHex(rgb) {
|
|
||||||
return componentToHex(rgb[0]) + componentToHex(rgb[1]) + componentToHex(rgb[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//display the touch/click position and color info
|
|
||||||
function updateStatus(pos, color) {
|
|
||||||
//var hexColor = rgbToHex(color);
|
|
||||||
//wsSetAll(hexColor);
|
|
||||||
var hexColor = componentToHex(color[0]) + componentToHex(color[1]) + componentToHex(color[2]);
|
|
||||||
wsSetMainColor(hexColor);
|
|
||||||
hexColor = "#" + hexColor;
|
|
||||||
|
|
||||||
$('#status').css("backgroundColor", hexColor);
|
|
||||||
$('#status_color').text(hexColor + " - R=" + color[0] + ", G=" + color[1] + ", B=" + color[2]);
|
|
||||||
$('#status_pos').text("x: " + pos.x + " - y: " + pos.y);
|
|
||||||
|
|
||||||
$("#rng_white").val(0);
|
|
||||||
$("#rng_red").val(color[0]);
|
|
||||||
$("#rng_green").val(color[1]);
|
|
||||||
$("#rng_blue").val(color[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//handle the touch event
|
|
||||||
function doTouch(event) {
|
|
||||||
//to not also fire on click
|
|
||||||
event.preventDefault();
|
|
||||||
var el = event.target;
|
|
||||||
|
|
||||||
//touch position
|
|
||||||
var pos = {x: Math.round(event.targetTouches[0].pageX - el.offsetLeft),
|
|
||||||
y: Math.round(event.targetTouches[0].pageY - el.offsetTop)};
|
|
||||||
//color
|
|
||||||
var color = context.getImageData(pos.x, pos.y, 1, 1).data;
|
|
||||||
|
|
||||||
updateStatus(pos, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
function doClick(event) {
|
|
||||||
//click position
|
|
||||||
var pos = getMousePos(canvas, event);
|
|
||||||
//color
|
|
||||||
var color = context.getImageData(pos.x, pos.y, 1, 1).data;
|
|
||||||
|
|
||||||
//console.log("click", pos.x, pos.y, color);
|
|
||||||
updateStatus(pos, color);
|
|
||||||
|
|
||||||
//now do sth with the color rgbToHex(color);
|
|
||||||
//don't do stuff when #000000 (outside circle and lines
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// main
|
|
||||||
// ******************************************************************
|
|
||||||
init();
|
|
||||||
|
|
||||||
}); // end of document ready
|
|
||||||
})(jQuery); // end of jQuery name space</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
var gulp = require('gulp'),
|
|
||||||
request = require('request'),
|
|
||||||
fs = require('fs'),
|
|
||||||
connect = require('gulp-connect'),
|
|
||||||
fileinclude = require('gulp-file-include');
|
|
||||||
|
|
||||||
var src_dir = "src/";
|
|
||||||
var build_dir = "build/";
|
|
||||||
|
|
||||||
|
|
||||||
gulp.task('html', function() {
|
|
||||||
gulp.src(src_dir + '*.htm')
|
|
||||||
.pipe(fileinclude({
|
|
||||||
prefix: '@@',
|
|
||||||
basepath: '@file'
|
|
||||||
}))
|
|
||||||
.pipe(gulp.dest('build'))
|
|
||||||
.pipe(connect.reload());
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
gulp.task('connect', function() {
|
|
||||||
connect.server({
|
|
||||||
root: 'build',
|
|
||||||
livereload: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('watch', function() {
|
|
||||||
gulp.watch(src_dir + '*.htm', ['html']);
|
|
||||||
gulp.watch(src_dir + 'js/*.js', ['html']);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
gulp.task('upload', ['html'], function() {
|
|
||||||
var url = 'http://192.168.0.49/edit';
|
|
||||||
var options = {
|
|
||||||
url: url,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'multipart/form-data'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var r = request.post(options, function optionalCallback(err, httpResponse, body) {
|
|
||||||
if (err) {
|
|
||||||
return console.error('upload failed:', err);
|
|
||||||
}
|
|
||||||
console.log('Upload successful! Server responded with:', body);
|
|
||||||
});
|
|
||||||
var form = r.form();
|
|
||||||
form.append('data', fs.createReadStream(__dirname + "/" + build_dir + '/index.htm'), {filename: '/index.htm', contentType: "application/octet-stream"});
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('default', ['html']);
|
|
||||||
gulp.task('serve', ['watch', 'connect']);
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "mc_lighting",
|
|
||||||
"version": "2.0.0",
|
|
||||||
"description": "Web client for Mc Lighting",
|
|
||||||
"main": "index.html",
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"author": "Tobias Blum",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"fs": "0.0.2",
|
|
||||||
"gulp": "^3.9.1",
|
|
||||||
"gulp-connect": "^5.0.0",
|
|
||||||
"gulp-file-include": "^1.0.0",
|
|
||||||
"request": "^2.72.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!--Import Google Icon Font-->
|
|
||||||
<link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
||||||
<!--Import materialize.css-->
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.min.css" media="screen,projection" />
|
|
||||||
|
|
||||||
<!--Let browser know website is optimized for mobile-->
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
|
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
|
||||||
<title>McLighting (RGBW) v2</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<nav class="blue light-blueXXX lighten-1XXX" role="navigation" id="mc-nav">
|
|
||||||
<div class="nav-wrapper container">
|
|
||||||
<a id="logo-container" href="#" class="brand-logo">McLighting (RGBW) v2</a>
|
|
||||||
|
|
||||||
<ul class="right hide-on-med-and-down">
|
|
||||||
<li><a href="#" class="mc-navlink" data-pane="pane1">Wheel</a></li>
|
|
||||||
<li><a href="#" class="mc-navlink" data-pane="pane2">Modes</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul id="nav-mobile" class="side-nav">
|
|
||||||
<li><a href="#" class="mc-navlink" data-pane="pane1">Wheel</a></li>
|
|
||||||
<li><a href="#" class="mc-navlink" data-pane="pane2">Modes</a></li>
|
|
||||||
</ul>
|
|
||||||
<a href="#" data-activates="nav-mobile" class="button-collapse"><i class="material-icons">menu</i></a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="container mc_pane" id="pane0">
|
|
||||||
<div class="section">
|
|
||||||
<div class="row" id="mc-wsloader">
|
|
||||||
<div class="col">
|
|
||||||
<div class="preloader-wrapper active">
|
|
||||||
<div class="spinner-layer spinner-blue-only">
|
|
||||||
<div class="circle-clipper left">
|
|
||||||
<div class="circle"></div>
|
|
||||||
</div>
|
|
||||||
<div class="gap-patch">
|
|
||||||
<div class="circle"></div>
|
|
||||||
</div>
|
|
||||||
<div class="circle-clipper right">
|
|
||||||
<div class="circle"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row hide" id="mc-wserror">
|
|
||||||
<div class="col">
|
|
||||||
<div>Error on websocket connect.</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container mc_pane hide" id="pane1">
|
|
||||||
<div class="section">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col s12 m6">
|
|
||||||
<div style="height: 330px; width: 330px;">
|
|
||||||
<canvas id="myCanvas" width="330" height="330" style="-webkit-user-select: none;-webkit-tap-highlight-color: rgba(0,0,0,0);-moz-user-select:none;"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col s12 m6">
|
|
||||||
<div class="card-panel" id="status">
|
|
||||||
<div id="status_pos">pick a color</div>
|
|
||||||
<div id="status_color"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col s12 m6">
|
|
||||||
<div class="right switch">Auto:<br>
|
|
||||||
<label>Off
|
|
||||||
<input id="autoSwitch" type="checkbox"><span class="lever"></span>On
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container mc_pane hide" id="pane2">
|
|
||||||
<div class="section">
|
|
||||||
<div class="row">
|
|
||||||
<form class="col s12">
|
|
||||||
<div class="row">
|
|
||||||
<div class="input-field col s12 l4">
|
|
||||||
<label for="txt_red">Red</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_red" min="0" max="255" class="update_colors" /></p>
|
|
||||||
</div>
|
|
||||||
<div class="input-field col s12 l4">
|
|
||||||
<label for="txt_green">Green</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_green" min="0" max="255" class="update_colors" /></p>
|
|
||||||
</div>
|
|
||||||
<div class="input-field col s12 l4">
|
|
||||||
<label for="txt_blue">Blue</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_blue" min="0" max="255" class="update_colors" /></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="input-field col s12">
|
|
||||||
<label for="txt_white">White</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_white" min="0" max="255" class="update_colors" /></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="input-field col s12">
|
|
||||||
<label for="txt_delay">Speed</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_delay" min="0" max="255" value="196" class="update_delay" /></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="input-field col s12">
|
|
||||||
<label for="txt_delay">Brightness</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_brightness" min="0" max="255" value="196" class="update_brightness" /></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div id="modes">
|
|
||||||
<div class="input-field col s12">
|
|
||||||
Loading animations...
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer class="page-footer blue">
|
|
||||||
<div class="footer-copyright">
|
|
||||||
<div class="container">© 2017
|
|
||||||
<a class="grey-text text-lighten-4 right" href="https://github.com/toblum/McLighting">Project home</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<style type="text/css">
|
|
||||||
.btn_grid {
|
|
||||||
margin: 7px 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<!--Import jQuery before materialize.js-->
|
|
||||||
<script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
|
|
||||||
<script type="text/javascript">@@include('js/script.js')</script>
|
|
||||||
</body>
|
|
||||||
\ No newline at end of file
|
|
||||||
</html>
|
|
||||||
@@ -1,331 +0,0 @@
|
|||||||
(function($){
|
|
||||||
$(function(){
|
|
||||||
|
|
||||||
// Settings
|
|
||||||
var host = window.location.hostname;
|
|
||||||
//host = "esp8266_02.local";
|
|
||||||
|
|
||||||
var ws_url = 'ws://' + host + ':81';
|
|
||||||
var connection;
|
|
||||||
var ws_waiting = 0;
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// Side navigation
|
|
||||||
// ******************************************************************
|
|
||||||
$('.button-collapse').sideNav();
|
|
||||||
|
|
||||||
// Navlinks
|
|
||||||
$('#mc-nav').on('click', '.mc-navlink', function(){
|
|
||||||
console.log("Navigate to pane: ", $(this).data("pane"));
|
|
||||||
showPane($(this).data("pane"));
|
|
||||||
});
|
|
||||||
|
|
||||||
function showPane(pane) {
|
|
||||||
$('.mc_pane').addClass('hide');
|
|
||||||
$('#' + pane).removeClass('hide');
|
|
||||||
$('.button-collapse').sideNav('hide');
|
|
||||||
|
|
||||||
//if (pane == "pane2") {
|
|
||||||
// setMainColor();
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// init()
|
|
||||||
// ******************************************************************
|
|
||||||
function init() {
|
|
||||||
console.log("Connection websockets to:", ws_url);
|
|
||||||
connection = new WebSocket(ws_url, ['arduino']);
|
|
||||||
var mode = 0;
|
|
||||||
var ws2812fx_mode = 0;
|
|
||||||
$.getJSON("http://" + host + "/status", function(data) {
|
|
||||||
console.log("status", data);
|
|
||||||
mode = data.mode;
|
|
||||||
ws2812fx_mode = data.ws2812fx_mode;
|
|
||||||
$("#rng_delay").val(data.speed);
|
|
||||||
$("#rng_brightness").val(data.brightness);
|
|
||||||
$("#rng_white").val(data.color[0]);
|
|
||||||
$("#rng_red").val(data.color[1]);
|
|
||||||
$("#rng_green").val(data.color[2]);
|
|
||||||
$("#rng_blue").val(data.color[3]);
|
|
||||||
var statusColor = "#" + componentToHex(data.color[1]) + componentToHex(data.color[2]) + componentToHex(data.color[3]);
|
|
||||||
$('#status').css("backgroundColor", statusColor);
|
|
||||||
$('#status_color').text(statusColor + "- R=" + data.color[1] + ", G=" + data.color[2] + ", B=" + data.color[3]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Load modes async
|
|
||||||
// List of all color modes
|
|
||||||
// enum MODE {OFF, AUTO, TV, E131, SET_MODE, HOLD, CUSTOM, SETCOLOR, SETSPEED, BRIGHTNESS, WIPE, RAINBOW, RAINBOWCYCLE, THEATERCHASE, TWINKLERANDOM, THEATERCHASERAINBOW};
|
|
||||||
$.getJSON("http://" + host + "/get_modes", function(data) {
|
|
||||||
console.log("modes", data);
|
|
||||||
var modes_html = "";
|
|
||||||
data.forEach(function(current_mode){
|
|
||||||
if (current_mode.mode !== undefined) {
|
|
||||||
modes_html += '<div class="col s12 m6 l6 btn_grid">';
|
|
||||||
if ((mode == "5" && current_mode.mode == ws2812fx_mode) || (mode == "0" && current_mode.mode == "off") || (mode == "2" && current_mode.mode == "tv") || (mode == "3" && current_mode.mode == "e131")){
|
|
||||||
modes_html += '<a class="btn waves-effect waves-light btn_mode red" name="action" data-mode="' + current_mode.mode + '">(' + current_mode.mode +') '+ current_mode.name;
|
|
||||||
} else {
|
|
||||||
modes_html += '<a class="btn waves-effect waves-light btn_mode blue" name="action" data-mode="' + current_mode.mode + '">(' + current_mode.mode +') '+ current_mode.name;
|
|
||||||
}
|
|
||||||
modes_html += '<i class="material-icons right">send</i>';
|
|
||||||
modes_html += '</a>';
|
|
||||||
modes_html += '</div>';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#modes').html(modes_html);
|
|
||||||
});
|
|
||||||
// When the connection is open, send some data to the server
|
|
||||||
connection.onopen = function () {
|
|
||||||
//connection.send('Ping'); // Send the message 'Ping' to the server
|
|
||||||
console.log('WebSocket Open');
|
|
||||||
showPane('pane1');
|
|
||||||
};
|
|
||||||
|
|
||||||
// Log errors
|
|
||||||
connection.onerror = function (error) {
|
|
||||||
console.log('WebSocket Error ' + error);
|
|
||||||
$('#mc-wsloader').addClass('hide');
|
|
||||||
$('#mc-wserror').removeClass('hide');
|
|
||||||
};
|
|
||||||
|
|
||||||
// Log messages from the server
|
|
||||||
connection.onmessage = function (e) {
|
|
||||||
console.log('WebSocket from server: ' + e.data);
|
|
||||||
ws_waiting = 0;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// Modes
|
|
||||||
// ******************************************************************
|
|
||||||
$("#pane2").on("click", ".btn_mode", function() {
|
|
||||||
var mode = $(this).attr("data-mode");
|
|
||||||
last_mode = mode;
|
|
||||||
var btn = $(this);
|
|
||||||
setMode(mode, function() {
|
|
||||||
$(".btn_mode, .btn_mode_static").removeClass("red").addClass("blue");
|
|
||||||
btn.removeClass("blue").addClass("red");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#pane2").on("click", ".btn_mode_static", function() {
|
|
||||||
var mode = $(this).attr("data-mode");
|
|
||||||
var btn = $(this);
|
|
||||||
|
|
||||||
wsSendCommand("=" + mode);
|
|
||||||
$(".btn_mode, .btn_mode_static").removeClass("red").addClass("blue");
|
|
||||||
btn.removeClass("blue").addClass("red");
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#pane2").on("change", ".update_colors", setMainColor);
|
|
||||||
|
|
||||||
$("#pane2").on("change", ".update_delay", function() {
|
|
||||||
var delay = $("#rng_delay").val();
|
|
||||||
|
|
||||||
wsSendCommand("?" + delay);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#pane2").on("change", ".update_brightness", function() {
|
|
||||||
var brightness = $("#rng_brightness").val();
|
|
||||||
|
|
||||||
wsSendCommand("%" + brightness);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#autoSwitch").on("change", function () {
|
|
||||||
if ($(this).prop('checked')) {
|
|
||||||
wsSendCommand("start");
|
|
||||||
} else {
|
|
||||||
wsSendCommand("stop");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function setMode(mode, finish_funtion) {
|
|
||||||
console.log("Mode: ", mode);
|
|
||||||
|
|
||||||
wsSendCommand("/" + mode);
|
|
||||||
finish_funtion();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setMainColor() {
|
|
||||||
var white = $("#rng_white").val();
|
|
||||||
var red = $("#rng_red").val();
|
|
||||||
var green = $("#rng_green").val();
|
|
||||||
var blue = $("#rng_blue").val();
|
|
||||||
|
|
||||||
var hexColor = componentToHex(white) + componentToHex(red) + componentToHex(green) + componentToHex(blue);
|
|
||||||
var statusColor = "#" + componentToHex(red) + componentToHex(green) + componentToHex(blue);
|
|
||||||
wsSetMainColor(hexColor);
|
|
||||||
$('#status').css("backgroundColor", statusColor);
|
|
||||||
$('#status_color').text(statusColor + "- R=" + red + ", G=" + green + ", B=" + blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// WebSocket commands
|
|
||||||
// ******************************************************************
|
|
||||||
function wsSendCommand(cmd) {
|
|
||||||
console.log("Send WebSocket command:", cmd);
|
|
||||||
if (ws_waiting == 0) {
|
|
||||||
connection.send(cmd);
|
|
||||||
ws_waiting++;
|
|
||||||
} else {
|
|
||||||
console.log("++++++++ WS call waiting, skip")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function wsSetAll(hexColor) {
|
|
||||||
console.log("wsSetAll() Set all colors to:", hexColor);
|
|
||||||
wsSendCommand("*" + hexColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
function wsSetMainColor(hexColor) {
|
|
||||||
console.log("wsSetMainColor() Set main colors to:", hexColor);
|
|
||||||
wsSendCommand("#" + hexColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// Colorwheel
|
|
||||||
// ******************************************************************
|
|
||||||
// this is supposed to work on mobiles (touch) as well as on a desktop (click)
|
|
||||||
// since we couldn't find a decent one .. this try of writing one by myself
|
|
||||||
// + google. swiping would be really nice - I will possibly implement it with
|
|
||||||
// jquery later - or never.
|
|
||||||
|
|
||||||
var canvas = document.getElementById("myCanvas");
|
|
||||||
// FIX: Cancel touch end event and handle click via touchstart
|
|
||||||
// canvas.addEventListener("touchend", function(e) { e.preventDefault(); }, false);
|
|
||||||
canvas.addEventListener("touchmove", doTouch, false);
|
|
||||||
canvas.addEventListener("click", doClick, false);
|
|
||||||
//canvas.addEventListener("mousemove", doClick, false);
|
|
||||||
|
|
||||||
|
|
||||||
var context = canvas.getContext('2d');
|
|
||||||
var centerX = canvas.width / 2;
|
|
||||||
var centerY = canvas.height / 2;
|
|
||||||
var innerRadius = canvas.width / 4.5;
|
|
||||||
var outerRadius = (canvas.width - 10) / 2
|
|
||||||
|
|
||||||
//outer border
|
|
||||||
context.beginPath();
|
|
||||||
//outer circle
|
|
||||||
context.arc(centerX, centerY, outerRadius, 0, 2 * Math.PI, false);
|
|
||||||
//draw the outer border: (gets drawn around the circle!)
|
|
||||||
context.lineWidth = 4;
|
|
||||||
context.strokeStyle = '#000000';
|
|
||||||
context.stroke();
|
|
||||||
context.closePath();
|
|
||||||
|
|
||||||
//fill with beautiful colors
|
|
||||||
//taken from here: http://stackoverflow.com/questions/18265804/building-a-color-wheel-in-html5
|
|
||||||
for(var angle=0; angle<=360; angle+=1) {
|
|
||||||
var startAngle = (angle-2)*Math.PI/180;
|
|
||||||
var endAngle = angle * Math.PI/180;
|
|
||||||
context.beginPath();
|
|
||||||
context.moveTo(centerX, centerY);
|
|
||||||
context.arc(centerX, centerY, outerRadius, startAngle, endAngle, false);
|
|
||||||
context.closePath();
|
|
||||||
context.fillStyle = 'hsl('+angle+', 100%, 50%)';
|
|
||||||
context.fill();
|
|
||||||
context.closePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
//inner border
|
|
||||||
context.beginPath();
|
|
||||||
//context.arc(centerX, centerY, radius, startAngle, endAngle, counterClockwise);
|
|
||||||
context.arc(centerX, centerY, innerRadius, 0, 2 * Math.PI, false);
|
|
||||||
//fill the center
|
|
||||||
var my_gradient=context.createLinearGradient(0,0,170,0);
|
|
||||||
my_gradient.addColorStop(0,"black");
|
|
||||||
my_gradient.addColorStop(1,"white");
|
|
||||||
|
|
||||||
context.fillStyle = my_gradient;
|
|
||||||
context.fillStyle = "white";
|
|
||||||
context.fill();
|
|
||||||
|
|
||||||
//draw the inner line
|
|
||||||
context.lineWidth = 2;
|
|
||||||
context.strokeStyle = '#000000';
|
|
||||||
context.stroke();
|
|
||||||
context.closePath();
|
|
||||||
|
|
||||||
//get Mouse x/y canvas position
|
|
||||||
function getMousePos(canvas, evt) {
|
|
||||||
var rect = canvas.getBoundingClientRect();
|
|
||||||
return {
|
|
||||||
x: evt.clientX - rect.left,
|
|
||||||
y: evt.clientY - rect.top
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//comp to Hex
|
|
||||||
function componentToHex(c) {
|
|
||||||
//var hex = c.toString(16);
|
|
||||||
//return hex.length == 1 ? "0" + hex : hex;
|
|
||||||
return ("0"+(Number(c).toString(16))).slice(-2).toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
//rgb/rgba to Hex
|
|
||||||
function rgbToHex(rgb) {
|
|
||||||
return componentToHex(rgb[0]) + componentToHex(rgb[1]) + componentToHex(rgb[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//display the touch/click position and color info
|
|
||||||
function updateStatus(pos, color) {
|
|
||||||
//var hexColor = rgbToHex(color);
|
|
||||||
//wsSetAll(hexColor);
|
|
||||||
var hexColor = componentToHex(color[0]) + componentToHex(color[1]) + componentToHex(color[2]);
|
|
||||||
wsSetMainColor(hexColor);
|
|
||||||
hexColor = "#" + hexColor;
|
|
||||||
|
|
||||||
$('#status').css("backgroundColor", hexColor);
|
|
||||||
$('#status_color').text(hexColor + " - R=" + color[0] + ", G=" + color[1] + ", B=" + color[2]);
|
|
||||||
$('#status_pos').text("x: " + pos.x + " - y: " + pos.y);
|
|
||||||
|
|
||||||
$("#rng_white").val(0);
|
|
||||||
$("#rng_red").val(color[0]);
|
|
||||||
$("#rng_green").val(color[1]);
|
|
||||||
$("#rng_blue").val(color[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//handle the touch event
|
|
||||||
function doTouch(event) {
|
|
||||||
//to not also fire on click
|
|
||||||
event.preventDefault();
|
|
||||||
var el = event.target;
|
|
||||||
|
|
||||||
//touch position
|
|
||||||
var pos = {x: Math.round(event.targetTouches[0].pageX - el.offsetLeft),
|
|
||||||
y: Math.round(event.targetTouches[0].pageY - el.offsetTop)};
|
|
||||||
//color
|
|
||||||
var color = context.getImageData(pos.x, pos.y, 1, 1).data;
|
|
||||||
|
|
||||||
updateStatus(pos, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
function doClick(event) {
|
|
||||||
//click position
|
|
||||||
var pos = getMousePos(canvas, event);
|
|
||||||
//color
|
|
||||||
var color = context.getImageData(pos.x, pos.y, 1, 1).data;
|
|
||||||
|
|
||||||
//console.log("click", pos.x, pos.y, color);
|
|
||||||
updateStatus(pos, color);
|
|
||||||
|
|
||||||
//now do sth with the color rgbToHex(color);
|
|
||||||
//don't do stuff when #000000 (outside circle and lines
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// main
|
|
||||||
// ******************************************************************
|
|
||||||
init();
|
|
||||||
|
|
||||||
}); // end of document ready
|
|
||||||
})(jQuery); // end of jQuery name space
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
## Retired, use:
|
|
||||||
McLightingHTML from https://github.com/FabLab-Luenen/McLightingHTML
|
|
||||||
|
|
||||||
or set #define USE_HTML_MIN_GZ in definitions.h to use the integrated!
|
|
||||||
@@ -1,466 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!--Import Google Icon Font-->
|
|
||||||
<link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
||||||
<!--Import materialize.css-->
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.min.css" media="screen,projection" />
|
|
||||||
|
|
||||||
<!--Let browser know website is optimized for mobile-->
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
|
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<title>McLighting v2</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<nav class="blue light-blueXXX lighten-1XXX" role="navigation" id="mc-nav">
|
|
||||||
<div class="nav-wrapper container">
|
|
||||||
<a id="logo-container" href="#" class="brand-logo">Mc Lighting v2</a>
|
|
||||||
|
|
||||||
<ul class="right hide-on-med-and-down">
|
|
||||||
<li><a href="#" class="mc-navlink" data-pane="pane1">Wheel</a></li>
|
|
||||||
<li><a href="#" class="mc-navlink" data-pane="pane2">Modes</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul id="nav-mobile" class="side-nav">
|
|
||||||
<li><a href="#" class="mc-navlink" data-pane="pane1">Wheel</a></li>
|
|
||||||
<li><a href="#" class="mc-navlink" data-pane="pane2">Modes</a></li>
|
|
||||||
</ul>
|
|
||||||
<a href="#" data-activates="nav-mobile" class="button-collapse"><i class="material-icons">menu</i></a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="container mc_pane" id="pane0">
|
|
||||||
<div class="section">
|
|
||||||
<div class="row" id="mc-wsloader">
|
|
||||||
<div class="col">
|
|
||||||
<div class="preloader-wrapper active">
|
|
||||||
<div class="spinner-layer spinner-blue-only">
|
|
||||||
<div class="circle-clipper left">
|
|
||||||
<div class="circle"></div>
|
|
||||||
</div>
|
|
||||||
<div class="gap-patch">
|
|
||||||
<div class="circle"></div>
|
|
||||||
</div>
|
|
||||||
<div class="circle-clipper right">
|
|
||||||
<div class="circle"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row hide" id="mc-wserror">
|
|
||||||
<div class="col">
|
|
||||||
<div>Error on websocket connect.</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container mc_pane hide" id="pane1">
|
|
||||||
<div class="section">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col s12 m6">
|
|
||||||
<div style="height: 330px; width: 330px;">
|
|
||||||
<canvas id="myCanvas" width="330" height="330" style="-webkit-user-select: none;-webkit-tap-highlight-color: rgba(0,0,0,0);-moz-user-select:none;"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col s12 m6">
|
|
||||||
<div class="card-panel" id="status">
|
|
||||||
<div id="status_pos">pick a color</div>
|
|
||||||
<div id="status_color"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col s12 m6">
|
|
||||||
<div class="right switch">Auto:<br>
|
|
||||||
<label>Off
|
|
||||||
<input id="autoSwitch" type="checkbox"><span class="lever"></span>On
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container mc_pane hide" id="pane2">
|
|
||||||
<div class="section">
|
|
||||||
<div class="row">
|
|
||||||
<form class="col s12">
|
|
||||||
<div class="row">
|
|
||||||
<div class="input-field col s12 l4">
|
|
||||||
<label for="txt_red">Red</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_red" min="0" max="255" class="update_colors" /></p>
|
|
||||||
</div>
|
|
||||||
<div class="input-field col s12 l4">
|
|
||||||
<label for="txt_green">Green</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_green" min="0" max="255" class="update_colors" /></p>
|
|
||||||
</div>
|
|
||||||
<div class="input-field col s12 l4">
|
|
||||||
<label for="txt_blue">Blue</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_blue" min="0" max="255" class="update_colors" /></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="input-field col s12">
|
|
||||||
<label for="txt_delay">Speed</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_delay" min="0" max="255" value="196" class="update_delay" /></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="input-field col s12">
|
|
||||||
<label for="txt_delay">Brightness</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_brightness" min="0" max="255" value="196" class="update_brightness" /></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col s12 m6 l6 btn_grid">
|
|
||||||
<a class="btn waves-effect waves-light btn_mode_static blue" name="action" data-mode="off">OFF
|
|
||||||
<i class="material-icons right">send</i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col s12 m6 l6 btn_grid">
|
|
||||||
<a class="btn waves-effect waves-light btn_mode_static blue" name="action" data-mode="tv">TV
|
|
||||||
<i class="material-icons right">send</i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="modes">
|
|
||||||
<div class="input-field col s12">
|
|
||||||
Loading animations...
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer class="page-footer blue">
|
|
||||||
<div class="footer-copyright">
|
|
||||||
<div class="container">© 2017
|
|
||||||
<a class="grey-text text-lighten-4 right" href="https://github.com/toblum/McLighting">Project home</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<style type="text/css">
|
|
||||||
.btn_grid {
|
|
||||||
margin: 7px 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<!--Import jQuery before materialize.js-->
|
|
||||||
<script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
|
|
||||||
<script type="text/javascript">(function($){
|
|
||||||
$(function(){
|
|
||||||
|
|
||||||
// Settings
|
|
||||||
var host = window.location.hostname;
|
|
||||||
//host = "esp8266_02.local";
|
|
||||||
|
|
||||||
var ws_url = 'ws://' + host + ':81';
|
|
||||||
var connection;
|
|
||||||
var ws_waiting = 0;
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// Side navigation
|
|
||||||
// ******************************************************************
|
|
||||||
$('.button-collapse').sideNav();
|
|
||||||
|
|
||||||
// Navlinks
|
|
||||||
$('#mc-nav').on('click', '.mc-navlink', function(){
|
|
||||||
console.log("Navigate to pane: ", $(this).data("pane"));
|
|
||||||
showPane($(this).data("pane"));
|
|
||||||
});
|
|
||||||
|
|
||||||
function showPane(pane) {
|
|
||||||
$('.mc_pane').addClass('hide');
|
|
||||||
$('#' + pane).removeClass('hide');
|
|
||||||
$('.button-collapse').sideNav('hide');
|
|
||||||
|
|
||||||
if (pane == "pane2") {
|
|
||||||
setMainColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// init()
|
|
||||||
// ******************************************************************
|
|
||||||
function init() {
|
|
||||||
console.log("Connection websockets to:", ws_url);
|
|
||||||
connection = new WebSocket(ws_url, ['arduino']);
|
|
||||||
|
|
||||||
// Load modes async
|
|
||||||
$.getJSON("http://" + host + "/get_modes", function(data) {
|
|
||||||
//console.log("modes", data);
|
|
||||||
|
|
||||||
var modes_html = "";
|
|
||||||
data.forEach(function(current_mode){
|
|
||||||
if (current_mode.mode !== undefined) {
|
|
||||||
modes_html += '<div class="col s12 m6 l6 btn_grid">';
|
|
||||||
modes_html += '<a class="btn waves-effect waves-light btn_mode blue" name="action" data-mode="' + current_mode.mode + '">(' + current_mode.mode +') '+ current_mode.name;
|
|
||||||
modes_html += '<i class="material-icons right">send</i>';
|
|
||||||
modes_html += '</a>';
|
|
||||||
modes_html += '</div>';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#modes').html(modes_html);
|
|
||||||
});
|
|
||||||
|
|
||||||
// When the connection is open, send some data to the server
|
|
||||||
connection.onopen = function () {
|
|
||||||
//connection.send('Ping'); // Send the message 'Ping' to the server
|
|
||||||
console.log('WebSocket Open');
|
|
||||||
showPane('pane1');
|
|
||||||
};
|
|
||||||
|
|
||||||
// Log errors
|
|
||||||
connection.onerror = function (error) {
|
|
||||||
console.log('WebSocket Error ' + error);
|
|
||||||
$('#mc-wsloader').addClass('hide');
|
|
||||||
$('#mc-wserror').removeClass('hide');
|
|
||||||
};
|
|
||||||
|
|
||||||
// Log messages from the server
|
|
||||||
connection.onmessage = function (e) {
|
|
||||||
console.log('WebSocket from server: ' + e.data);
|
|
||||||
ws_waiting = 0;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// Modes
|
|
||||||
// ******************************************************************
|
|
||||||
$("#pane2").on("click", ".btn_mode", function() {
|
|
||||||
var mode = $(this).attr("data-mode");
|
|
||||||
last_mode = mode;
|
|
||||||
var btn = $(this);
|
|
||||||
setMode(mode, function() {
|
|
||||||
$(".btn_mode, .btn_mode_static").removeClass("red").addClass("blue");
|
|
||||||
btn.removeClass("blue").addClass("red");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#pane2").on("click", ".btn_mode_static", function() {
|
|
||||||
var mode = $(this).attr("data-mode");
|
|
||||||
var btn = $(this);
|
|
||||||
|
|
||||||
wsSendCommand("=" + mode);
|
|
||||||
$(".btn_mode, .btn_mode_static").removeClass("red").addClass("blue");
|
|
||||||
btn.removeClass("blue").addClass("red");
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#pane2").on("change", ".update_colors", setMainColor);
|
|
||||||
|
|
||||||
$("#pane2").on("change", ".update_delay", function() {
|
|
||||||
var delay = $("#rng_delay").val();
|
|
||||||
|
|
||||||
wsSendCommand("?" + delay);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#pane2").on("change", ".update_brightness", function() {
|
|
||||||
var brightness = $("#rng_brightness").val();
|
|
||||||
|
|
||||||
wsSendCommand("%" + brightness);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#autoSwitch").on("change", function () {
|
|
||||||
if ($(this).prop('checked')) {
|
|
||||||
wsSendCommand("start");
|
|
||||||
} else {
|
|
||||||
wsSendCommand("stop");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function setMode(mode, finish_funtion) {
|
|
||||||
console.log("Mode: ", mode);
|
|
||||||
|
|
||||||
wsSendCommand("/" + mode);
|
|
||||||
finish_funtion();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setMainColor() {
|
|
||||||
var red = $("#rng_red").val();
|
|
||||||
var green = $("#rng_green").val();
|
|
||||||
var blue = $("#rng_blue").val();
|
|
||||||
|
|
||||||
var mainColorHex = componentToHex(red) + componentToHex(green) + componentToHex(blue);
|
|
||||||
wsSetMainColor(mainColorHex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// WebSocket commands
|
|
||||||
// ******************************************************************
|
|
||||||
function wsSendCommand(cmd) {
|
|
||||||
console.log("Send WebSocket command:", cmd);
|
|
||||||
if (ws_waiting == 0) {
|
|
||||||
connection.send(cmd);
|
|
||||||
ws_waiting++;
|
|
||||||
} else {
|
|
||||||
console.log("++++++++ WS call waiting, skip")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function wsSetAll(hexColor) {
|
|
||||||
console.log("wsSetAll() Set all colors to:", hexColor);
|
|
||||||
wsSendCommand("*" + hexColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
function wsSetMainColor(hexColor) {
|
|
||||||
console.log("wsSetMainColor() Set main colors to:", hexColor);
|
|
||||||
wsSendCommand("#" + hexColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// Colorwheel
|
|
||||||
// ******************************************************************
|
|
||||||
// this is supposed to work on mobiles (touch) as well as on a desktop (click)
|
|
||||||
// since we couldn't find a decent one .. this try of writing one by myself
|
|
||||||
// + google. swiping would be really nice - I will possibly implement it with
|
|
||||||
// jquery later - or never.
|
|
||||||
|
|
||||||
var canvas = document.getElementById("myCanvas");
|
|
||||||
// FIX: Cancel touch end event and handle click via touchstart
|
|
||||||
// canvas.addEventListener("touchend", function(e) { e.preventDefault(); }, false);
|
|
||||||
canvas.addEventListener("touchmove", doTouch, false);
|
|
||||||
canvas.addEventListener("click", doClick, false);
|
|
||||||
//canvas.addEventListener("mousemove", doClick, false);
|
|
||||||
|
|
||||||
|
|
||||||
var context = canvas.getContext('2d');
|
|
||||||
var centerX = canvas.width / 2;
|
|
||||||
var centerY = canvas.height / 2;
|
|
||||||
var innerRadius = canvas.width / 4.5;
|
|
||||||
var outerRadius = (canvas.width - 10) / 2
|
|
||||||
|
|
||||||
//outer border
|
|
||||||
context.beginPath();
|
|
||||||
//outer circle
|
|
||||||
context.arc(centerX, centerY, outerRadius, 0, 2 * Math.PI, false);
|
|
||||||
//draw the outer border: (gets drawn around the circle!)
|
|
||||||
context.lineWidth = 4;
|
|
||||||
context.strokeStyle = '#000000';
|
|
||||||
context.stroke();
|
|
||||||
context.closePath();
|
|
||||||
|
|
||||||
//fill with beautiful colors
|
|
||||||
//taken from here: http://stackoverflow.com/questions/18265804/building-a-color-wheel-in-html5
|
|
||||||
for(var angle=0; angle<=360; angle+=1) {
|
|
||||||
var startAngle = (angle-2)*Math.PI/180;
|
|
||||||
var endAngle = angle * Math.PI/180;
|
|
||||||
context.beginPath();
|
|
||||||
context.moveTo(centerX, centerY);
|
|
||||||
context.arc(centerX, centerY, outerRadius, startAngle, endAngle, false);
|
|
||||||
context.closePath();
|
|
||||||
context.fillStyle = 'hsl('+angle+', 100%, 50%)';
|
|
||||||
context.fill();
|
|
||||||
context.closePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
//inner border
|
|
||||||
context.beginPath();
|
|
||||||
//context.arc(centerX, centerY, radius, startAngle, endAngle, counterClockwise);
|
|
||||||
context.arc(centerX, centerY, innerRadius, 0, 2 * Math.PI, false);
|
|
||||||
//fill the center
|
|
||||||
var my_gradient=context.createLinearGradient(0,0,170,0);
|
|
||||||
my_gradient.addColorStop(0,"black");
|
|
||||||
my_gradient.addColorStop(1,"white");
|
|
||||||
|
|
||||||
context.fillStyle = my_gradient;
|
|
||||||
context.fillStyle = "white";
|
|
||||||
context.fill();
|
|
||||||
|
|
||||||
//draw the inner line
|
|
||||||
context.lineWidth = 2;
|
|
||||||
context.strokeStyle = '#000000';
|
|
||||||
context.stroke();
|
|
||||||
context.closePath();
|
|
||||||
|
|
||||||
//get Mouse x/y canvas position
|
|
||||||
function getMousePos(canvas, evt) {
|
|
||||||
var rect = canvas.getBoundingClientRect();
|
|
||||||
return {
|
|
||||||
x: evt.clientX - rect.left,
|
|
||||||
y: evt.clientY - rect.top
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//comp to Hex
|
|
||||||
function componentToHex(c) {
|
|
||||||
//var hex = c.toString(16);
|
|
||||||
//return hex.length == 1 ? "0" + hex : hex;
|
|
||||||
return ("0"+(Number(c).toString(16))).slice(-2).toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
//rgb/rgba to Hex
|
|
||||||
function rgbToHex(rgb) {
|
|
||||||
return componentToHex(rgb[0]) + componentToHex(rgb[1]) + componentToHex(rgb[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//display the touch/click position and color info
|
|
||||||
function updateStatus(pos, color) {
|
|
||||||
var hexColor = rgbToHex(color);
|
|
||||||
wsSetAll(hexColor);
|
|
||||||
|
|
||||||
hexColor = "#" + hexColor;
|
|
||||||
|
|
||||||
$('#status').css("backgroundColor", hexColor);
|
|
||||||
$('#status_color').text(hexColor + " - R=" + color[0] + ", G=" + color[1] + ", B=" + color[2]);
|
|
||||||
$('#status_pos').text("x: " + pos.x + " - y: " + pos.y);
|
|
||||||
|
|
||||||
$("#rng_red").val(color[0]);
|
|
||||||
$("#rng_green").val(color[1]);
|
|
||||||
$("#rng_blue").val(color[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//handle the touch event
|
|
||||||
function doTouch(event) {
|
|
||||||
//to not also fire on click
|
|
||||||
event.preventDefault();
|
|
||||||
var el = event.target;
|
|
||||||
|
|
||||||
//touch position
|
|
||||||
var pos = {x: Math.round(event.targetTouches[0].pageX - el.offsetLeft),
|
|
||||||
y: Math.round(event.targetTouches[0].pageY - el.offsetTop)};
|
|
||||||
//color
|
|
||||||
var color = context.getImageData(pos.x, pos.y, 1, 1).data;
|
|
||||||
|
|
||||||
updateStatus(pos, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
function doClick(event) {
|
|
||||||
//click position
|
|
||||||
var pos = getMousePos(canvas, event);
|
|
||||||
//color
|
|
||||||
var color = context.getImageData(pos.x, pos.y, 1, 1).data;
|
|
||||||
|
|
||||||
//console.log("click", pos.x, pos.y, color);
|
|
||||||
updateStatus(pos, color);
|
|
||||||
|
|
||||||
//now do sth with the color rgbToHex(color);
|
|
||||||
//don't do stuff when #000000 (outside circle and lines
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// main
|
|
||||||
// ******************************************************************
|
|
||||||
init();
|
|
||||||
|
|
||||||
}); // end of document ready
|
|
||||||
})(jQuery); // end of jQuery name space</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
var gulp = require('gulp'),
|
|
||||||
request = require('request'),
|
|
||||||
fs = require('fs'),
|
|
||||||
connect = require('gulp-connect'),
|
|
||||||
fileinclude = require('gulp-file-include');
|
|
||||||
|
|
||||||
var src_dir = "src/";
|
|
||||||
var build_dir = "build/";
|
|
||||||
|
|
||||||
|
|
||||||
gulp.task('html', function() {
|
|
||||||
gulp.src(src_dir + '*.htm')
|
|
||||||
.pipe(fileinclude({
|
|
||||||
prefix: '@@',
|
|
||||||
basepath: '@file'
|
|
||||||
}))
|
|
||||||
.pipe(gulp.dest('build'))
|
|
||||||
.pipe(connect.reload());
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
gulp.task('connect', function() {
|
|
||||||
connect.server({
|
|
||||||
root: 'build',
|
|
||||||
livereload: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('watch', function() {
|
|
||||||
gulp.watch(src_dir + '*.htm', ['html']);
|
|
||||||
gulp.watch(src_dir + 'js/*.js', ['html']);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
gulp.task('upload', ['html'], function() {
|
|
||||||
var url = 'http://192.168.0.49/edit';
|
|
||||||
var options = {
|
|
||||||
url: url,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'multipart/form-data'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var r = request.post(options, function optionalCallback(err, httpResponse, body) {
|
|
||||||
if (err) {
|
|
||||||
return console.error('upload failed:', err);
|
|
||||||
}
|
|
||||||
console.log('Upload successful! Server responded with:', body);
|
|
||||||
});
|
|
||||||
var form = r.form();
|
|
||||||
form.append('data', fs.createReadStream(__dirname + "/" + build_dir + '/index.htm'), {filename: '/index.htm', contentType: "application/octet-stream"});
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('default', ['html']);
|
|
||||||
gulp.task('serve', ['watch', 'connect']);
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "mc_lighting",
|
|
||||||
"version": "2.0.0",
|
|
||||||
"description": "Web client for Mc Lighting",
|
|
||||||
"main": "index.html",
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"author": "Tobias Blum",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"fs": "0.0.2",
|
|
||||||
"gulp": "^3.9.1",
|
|
||||||
"gulp-connect": "^5.0.0",
|
|
||||||
"gulp-file-include": "^1.0.0",
|
|
||||||
"request": "^2.72.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!--Import Google Icon Font-->
|
|
||||||
<link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
||||||
<!--Import materialize.css-->
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.min.css" media="screen,projection" />
|
|
||||||
|
|
||||||
<!--Let browser know website is optimized for mobile-->
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
|
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<title>McLighting v2</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<nav class="blue light-blueXXX lighten-1XXX" role="navigation" id="mc-nav">
|
|
||||||
<div class="nav-wrapper container">
|
|
||||||
<a id="logo-container" href="#" class="brand-logo">Mc Lighting v2</a>
|
|
||||||
|
|
||||||
<ul class="right hide-on-med-and-down">
|
|
||||||
<li><a href="#" class="mc-navlink" data-pane="pane1">Wheel</a></li>
|
|
||||||
<li><a href="#" class="mc-navlink" data-pane="pane2">Modes</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul id="nav-mobile" class="side-nav">
|
|
||||||
<li><a href="#" class="mc-navlink" data-pane="pane1">Wheel</a></li>
|
|
||||||
<li><a href="#" class="mc-navlink" data-pane="pane2">Modes</a></li>
|
|
||||||
</ul>
|
|
||||||
<a href="#" data-activates="nav-mobile" class="button-collapse"><i class="material-icons">menu</i></a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="container mc_pane" id="pane0">
|
|
||||||
<div class="section">
|
|
||||||
<div class="row" id="mc-wsloader">
|
|
||||||
<div class="col">
|
|
||||||
<div class="preloader-wrapper active">
|
|
||||||
<div class="spinner-layer spinner-blue-only">
|
|
||||||
<div class="circle-clipper left">
|
|
||||||
<div class="circle"></div>
|
|
||||||
</div>
|
|
||||||
<div class="gap-patch">
|
|
||||||
<div class="circle"></div>
|
|
||||||
</div>
|
|
||||||
<div class="circle-clipper right">
|
|
||||||
<div class="circle"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row hide" id="mc-wserror">
|
|
||||||
<div class="col">
|
|
||||||
<div>Error on websocket connect.</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container mc_pane hide" id="pane1">
|
|
||||||
<div class="section">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col s12 m6">
|
|
||||||
<div style="height: 330px; width: 330px;">
|
|
||||||
<canvas id="myCanvas" width="330" height="330" style="-webkit-user-select: none;-webkit-tap-highlight-color: rgba(0,0,0,0);-moz-user-select:none;"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col s12 m6">
|
|
||||||
<div class="card-panel" id="status">
|
|
||||||
<div id="status_pos">pick a color</div>
|
|
||||||
<div id="status_color"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col s12 m6">
|
|
||||||
<div class="right switch">Auto:<br>
|
|
||||||
<label>Off
|
|
||||||
<input id="autoSwitch" type="checkbox"><span class="lever"></span>On
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container mc_pane hide" id="pane2">
|
|
||||||
<div class="section">
|
|
||||||
<div class="row">
|
|
||||||
<form class="col s12">
|
|
||||||
<div class="row">
|
|
||||||
<div class="input-field col s12 l4">
|
|
||||||
<label for="txt_red">Red</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_red" min="0" max="255" class="update_colors" /></p>
|
|
||||||
</div>
|
|
||||||
<div class="input-field col s12 l4">
|
|
||||||
<label for="txt_green">Green</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_green" min="0" max="255" class="update_colors" /></p>
|
|
||||||
</div>
|
|
||||||
<div class="input-field col s12 l4">
|
|
||||||
<label for="txt_blue">Blue</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_blue" min="0" max="255" class="update_colors" /></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="input-field col s12">
|
|
||||||
<label for="txt_delay">Speed</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_delay" min="0" max="255" value="196" class="update_delay" /></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="input-field col s12">
|
|
||||||
<label for="txt_delay">Brightness</label><br/>
|
|
||||||
<p class="range-field"><input type="range" id="rng_brightness" min="0" max="255" value="196" class="update_brightness" /></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col s12 m6 l6 btn_grid">
|
|
||||||
<a class="btn waves-effect waves-light btn_mode_static blue" name="action" data-mode="off">OFF
|
|
||||||
<i class="material-icons right">send</i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col s12 m6 l6 btn_grid">
|
|
||||||
<a class="btn waves-effect waves-light btn_mode_static blue" name="action" data-mode="tv">TV
|
|
||||||
<i class="material-icons right">send</i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="modes">
|
|
||||||
<div class="input-field col s12">
|
|
||||||
Loading animations...
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer class="page-footer blue">
|
|
||||||
<div class="footer-copyright">
|
|
||||||
<div class="container">© 2017
|
|
||||||
<a class="grey-text text-lighten-4 right" href="https://github.com/toblum/McLighting">Project home</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<style type="text/css">
|
|
||||||
.btn_grid {
|
|
||||||
margin: 7px 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<!--Import jQuery before materialize.js-->
|
|
||||||
<script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
|
|
||||||
<script type="text/javascript">@@include('js/script.js')</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,305 +0,0 @@
|
|||||||
(function($){
|
|
||||||
$(function(){
|
|
||||||
|
|
||||||
// Settings
|
|
||||||
var host = window.location.hostname;
|
|
||||||
//host = "esp8266_02.local";
|
|
||||||
|
|
||||||
var ws_url = 'ws://' + host + ':81';
|
|
||||||
var connection;
|
|
||||||
var ws_waiting = 0;
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// Side navigation
|
|
||||||
// ******************************************************************
|
|
||||||
$('.button-collapse').sideNav();
|
|
||||||
|
|
||||||
// Navlinks
|
|
||||||
$('#mc-nav').on('click', '.mc-navlink', function(){
|
|
||||||
console.log("Navigate to pane: ", $(this).data("pane"));
|
|
||||||
showPane($(this).data("pane"));
|
|
||||||
});
|
|
||||||
|
|
||||||
function showPane(pane) {
|
|
||||||
$('.mc_pane').addClass('hide');
|
|
||||||
$('#' + pane).removeClass('hide');
|
|
||||||
$('.button-collapse').sideNav('hide');
|
|
||||||
|
|
||||||
if (pane == "pane2") {
|
|
||||||
setMainColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// init()
|
|
||||||
// ******************************************************************
|
|
||||||
function init() {
|
|
||||||
console.log("Connection websockets to:", ws_url);
|
|
||||||
connection = new WebSocket(ws_url, ['arduino']);
|
|
||||||
|
|
||||||
// Load modes async
|
|
||||||
$.getJSON("http://" + host + "/get_modes", function(data) {
|
|
||||||
//console.log("modes", data);
|
|
||||||
|
|
||||||
var modes_html = "";
|
|
||||||
data.forEach(function(current_mode){
|
|
||||||
if (current_mode.mode !== undefined) {
|
|
||||||
modes_html += '<div class="col s12 m6 l6 btn_grid">';
|
|
||||||
modes_html += '<a class="btn waves-effect waves-light btn_mode blue" name="action" data-mode="' + current_mode.mode + '">(' + current_mode.mode +') '+ current_mode.name;
|
|
||||||
modes_html += '<i class="material-icons right">send</i>';
|
|
||||||
modes_html += '</a>';
|
|
||||||
modes_html += '</div>';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#modes').html(modes_html);
|
|
||||||
});
|
|
||||||
|
|
||||||
// When the connection is open, send some data to the server
|
|
||||||
connection.onopen = function () {
|
|
||||||
//connection.send('Ping'); // Send the message 'Ping' to the server
|
|
||||||
console.log('WebSocket Open');
|
|
||||||
showPane('pane1');
|
|
||||||
};
|
|
||||||
|
|
||||||
// Log errors
|
|
||||||
connection.onerror = function (error) {
|
|
||||||
console.log('WebSocket Error ' + error);
|
|
||||||
$('#mc-wsloader').addClass('hide');
|
|
||||||
$('#mc-wserror').removeClass('hide');
|
|
||||||
};
|
|
||||||
|
|
||||||
// Log messages from the server
|
|
||||||
connection.onmessage = function (e) {
|
|
||||||
console.log('WebSocket from server: ' + e.data);
|
|
||||||
ws_waiting = 0;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// Modes
|
|
||||||
// ******************************************************************
|
|
||||||
$("#pane2").on("click", ".btn_mode", function() {
|
|
||||||
var mode = $(this).attr("data-mode");
|
|
||||||
last_mode = mode;
|
|
||||||
var btn = $(this);
|
|
||||||
setMode(mode, function() {
|
|
||||||
$(".btn_mode, .btn_mode_static").removeClass("red").addClass("blue");
|
|
||||||
btn.removeClass("blue").addClass("red");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#pane2").on("click", ".btn_mode_static", function() {
|
|
||||||
var mode = $(this).attr("data-mode");
|
|
||||||
var btn = $(this);
|
|
||||||
|
|
||||||
wsSendCommand("=" + mode);
|
|
||||||
$(".btn_mode, .btn_mode_static").removeClass("red").addClass("blue");
|
|
||||||
btn.removeClass("blue").addClass("red");
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#pane2").on("change", ".update_colors", setMainColor);
|
|
||||||
|
|
||||||
$("#pane2").on("change", ".update_delay", function() {
|
|
||||||
var delay = $("#rng_delay").val();
|
|
||||||
|
|
||||||
wsSendCommand("?" + delay);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#pane2").on("change", ".update_brightness", function() {
|
|
||||||
var brightness = $("#rng_brightness").val();
|
|
||||||
|
|
||||||
wsSendCommand("%" + brightness);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#autoSwitch").on("change", function () {
|
|
||||||
if ($(this).prop('checked')) {
|
|
||||||
wsSendCommand("start");
|
|
||||||
} else {
|
|
||||||
wsSendCommand("stop");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function setMode(mode, finish_funtion) {
|
|
||||||
console.log("Mode: ", mode);
|
|
||||||
|
|
||||||
wsSendCommand("/" + mode);
|
|
||||||
finish_funtion();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setMainColor() {
|
|
||||||
var red = $("#rng_red").val();
|
|
||||||
var green = $("#rng_green").val();
|
|
||||||
var blue = $("#rng_blue").val();
|
|
||||||
|
|
||||||
var mainColorHex = componentToHex(red) + componentToHex(green) + componentToHex(blue);
|
|
||||||
wsSetMainColor(mainColorHex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// WebSocket commands
|
|
||||||
// ******************************************************************
|
|
||||||
function wsSendCommand(cmd) {
|
|
||||||
console.log("Send WebSocket command:", cmd);
|
|
||||||
if (ws_waiting == 0) {
|
|
||||||
connection.send(cmd);
|
|
||||||
ws_waiting++;
|
|
||||||
} else {
|
|
||||||
console.log("++++++++ WS call waiting, skip")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function wsSetAll(hexColor) {
|
|
||||||
console.log("wsSetAll() Set all colors to:", hexColor);
|
|
||||||
wsSendCommand("*" + hexColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
function wsSetMainColor(hexColor) {
|
|
||||||
console.log("wsSetMainColor() Set main colors to:", hexColor);
|
|
||||||
wsSendCommand("#" + hexColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// Colorwheel
|
|
||||||
// ******************************************************************
|
|
||||||
// this is supposed to work on mobiles (touch) as well as on a desktop (click)
|
|
||||||
// since we couldn't find a decent one .. this try of writing one by myself
|
|
||||||
// + google. swiping would be really nice - I will possibly implement it with
|
|
||||||
// jquery later - or never.
|
|
||||||
|
|
||||||
var canvas = document.getElementById("myCanvas");
|
|
||||||
// FIX: Cancel touch end event and handle click via touchstart
|
|
||||||
// canvas.addEventListener("touchend", function(e) { e.preventDefault(); }, false);
|
|
||||||
canvas.addEventListener("touchmove", doTouch, false);
|
|
||||||
canvas.addEventListener("click", doClick, false);
|
|
||||||
//canvas.addEventListener("mousemove", doClick, false);
|
|
||||||
|
|
||||||
|
|
||||||
var context = canvas.getContext('2d');
|
|
||||||
var centerX = canvas.width / 2;
|
|
||||||
var centerY = canvas.height / 2;
|
|
||||||
var innerRadius = canvas.width / 4.5;
|
|
||||||
var outerRadius = (canvas.width - 10) / 2
|
|
||||||
|
|
||||||
//outer border
|
|
||||||
context.beginPath();
|
|
||||||
//outer circle
|
|
||||||
context.arc(centerX, centerY, outerRadius, 0, 2 * Math.PI, false);
|
|
||||||
//draw the outer border: (gets drawn around the circle!)
|
|
||||||
context.lineWidth = 4;
|
|
||||||
context.strokeStyle = '#000000';
|
|
||||||
context.stroke();
|
|
||||||
context.closePath();
|
|
||||||
|
|
||||||
//fill with beautiful colors
|
|
||||||
//taken from here: http://stackoverflow.com/questions/18265804/building-a-color-wheel-in-html5
|
|
||||||
for(var angle=0; angle<=360; angle+=1) {
|
|
||||||
var startAngle = (angle-2)*Math.PI/180;
|
|
||||||
var endAngle = angle * Math.PI/180;
|
|
||||||
context.beginPath();
|
|
||||||
context.moveTo(centerX, centerY);
|
|
||||||
context.arc(centerX, centerY, outerRadius, startAngle, endAngle, false);
|
|
||||||
context.closePath();
|
|
||||||
context.fillStyle = 'hsl('+angle+', 100%, 50%)';
|
|
||||||
context.fill();
|
|
||||||
context.closePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
//inner border
|
|
||||||
context.beginPath();
|
|
||||||
//context.arc(centerX, centerY, radius, startAngle, endAngle, counterClockwise);
|
|
||||||
context.arc(centerX, centerY, innerRadius, 0, 2 * Math.PI, false);
|
|
||||||
//fill the center
|
|
||||||
var my_gradient=context.createLinearGradient(0,0,170,0);
|
|
||||||
my_gradient.addColorStop(0,"black");
|
|
||||||
my_gradient.addColorStop(1,"white");
|
|
||||||
|
|
||||||
context.fillStyle = my_gradient;
|
|
||||||
context.fillStyle = "white";
|
|
||||||
context.fill();
|
|
||||||
|
|
||||||
//draw the inner line
|
|
||||||
context.lineWidth = 2;
|
|
||||||
context.strokeStyle = '#000000';
|
|
||||||
context.stroke();
|
|
||||||
context.closePath();
|
|
||||||
|
|
||||||
//get Mouse x/y canvas position
|
|
||||||
function getMousePos(canvas, evt) {
|
|
||||||
var rect = canvas.getBoundingClientRect();
|
|
||||||
return {
|
|
||||||
x: evt.clientX - rect.left,
|
|
||||||
y: evt.clientY - rect.top
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//comp to Hex
|
|
||||||
function componentToHex(c) {
|
|
||||||
//var hex = c.toString(16);
|
|
||||||
//return hex.length == 1 ? "0" + hex : hex;
|
|
||||||
return ("0"+(Number(c).toString(16))).slice(-2).toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
//rgb/rgba to Hex
|
|
||||||
function rgbToHex(rgb) {
|
|
||||||
return componentToHex(rgb[0]) + componentToHex(rgb[1]) + componentToHex(rgb[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//display the touch/click position and color info
|
|
||||||
function updateStatus(pos, color) {
|
|
||||||
var hexColor = rgbToHex(color);
|
|
||||||
wsSetAll(hexColor);
|
|
||||||
|
|
||||||
hexColor = "#" + hexColor;
|
|
||||||
|
|
||||||
$('#status').css("backgroundColor", hexColor);
|
|
||||||
$('#status_color').text(hexColor + " - R=" + color[0] + ", G=" + color[1] + ", B=" + color[2]);
|
|
||||||
$('#status_pos').text("x: " + pos.x + " - y: " + pos.y);
|
|
||||||
|
|
||||||
$("#rng_red").val(color[0]);
|
|
||||||
$("#rng_green").val(color[1]);
|
|
||||||
$("#rng_blue").val(color[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//handle the touch event
|
|
||||||
function doTouch(event) {
|
|
||||||
//to not also fire on click
|
|
||||||
event.preventDefault();
|
|
||||||
var el = event.target;
|
|
||||||
|
|
||||||
//touch position
|
|
||||||
var pos = {x: Math.round(event.targetTouches[0].pageX - el.offsetLeft),
|
|
||||||
y: Math.round(event.targetTouches[0].pageY - el.offsetTop)};
|
|
||||||
//color
|
|
||||||
var color = context.getImageData(pos.x, pos.y, 1, 1).data;
|
|
||||||
|
|
||||||
updateStatus(pos, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
function doClick(event) {
|
|
||||||
//click position
|
|
||||||
var pos = getMousePos(canvas, event);
|
|
||||||
//color
|
|
||||||
var color = context.getImageData(pos.x, pos.y, 1, 1).data;
|
|
||||||
|
|
||||||
//console.log("click", pos.x, pos.y, color);
|
|
||||||
updateStatus(pos, color);
|
|
||||||
|
|
||||||
//now do sth with the color rgbToHex(color);
|
|
||||||
//don't do stuff when #000000 (outside circle and lines
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ******************************************************************
|
|
||||||
// main
|
|
||||||
// ******************************************************************
|
|
||||||
init();
|
|
||||||
|
|
||||||
}); // end of document ready
|
|
||||||
})(jQuery); // end of jQuery name space
|
|
||||||
Reference in New Issue
Block a user