kopia lustrzana https://github.com/Aircoookie/WLED
				
				
				
			CCT (color white balance support)
							rodzic
							
								
									00f1b483eb
								
							
						
					
					
						commit
						39b7b3ad53
					
				|  | @ -247,7 +247,7 @@ class WS2812FX { | |||
|    | ||||
|   // segment parameters
 | ||||
|   public: | ||||
|     typedef struct Segment { // 29 (32 in memory?) bytes
 | ||||
|     typedef struct Segment { // 30 (33 in memory?) bytes
 | ||||
|       uint16_t start; | ||||
|       uint16_t stop; //segment invalid if stop == 0
 | ||||
|       uint16_t offset; | ||||
|  | @ -259,6 +259,7 @@ class WS2812FX { | |||
|       uint8_t grouping, spacing; | ||||
|       uint8_t opacity; | ||||
|       uint32_t colors[NUM_COLORS]; | ||||
|       uint8_t cct; | ||||
|       char *name; | ||||
|       bool setColor(uint8_t slot, uint32_t c, uint8_t segn) { //returns true if changed
 | ||||
|         if (slot >= NUM_COLORS || segn >= MAX_NUM_SEGMENTS) return false; | ||||
|  |  | |||
|  | @ -220,6 +220,17 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) | |||
|     uint16_t realIndex = realPixelIndex(i); | ||||
|     uint16_t len = SEGMENT.length(); | ||||
| 
 | ||||
|     // determine if we can do white balance
 | ||||
|     int16_t cct = -1; | ||||
|     for (uint8_t b = 0; b < busses.getNumBusses(); b++) { | ||||
|       Bus *bus = busses.getBus(b); | ||||
|       if (bus == nullptr || !bus->containsPixel(realIndex)) continue; | ||||
|       if (allowCCT || bus->getType() == TYPE_ANALOG_2CH || bus->getType() == TYPE_ANALOG_5CH) { | ||||
|         cct = SEGMENT.cct; | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     for (uint16_t j = 0; j < SEGMENT.grouping; j++) { | ||||
|       uint16_t indexSet = realIndex + (IS_REVERSE ? -j : j); | ||||
|       if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) { | ||||
|  | @ -230,14 +241,14 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) | |||
|           if (indexMir >= SEGMENT.stop) indexMir -= len; | ||||
| 
 | ||||
|           if (indexMir < customMappingSize) indexMir = customMappingTable[indexMir]; | ||||
|           busses.setPixelColor(indexMir, col); | ||||
|           busses.setPixelColor(indexMir, col, cct); | ||||
|         } | ||||
|         /* offset/phase */ | ||||
|         indexSet += SEGMENT.offset; | ||||
|         if (indexSet >= SEGMENT.stop) indexSet -= len; | ||||
| 
 | ||||
|         if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet]; | ||||
|         busses.setPixelColor(indexSet, col); | ||||
|         busses.setPixelColor(indexSet, col, cct); | ||||
|       } | ||||
|     } | ||||
|   } else { //live data, etc.
 | ||||
|  | @ -623,6 +634,7 @@ void WS2812FX::resetSegments() { | |||
|   _segments[0].setOption(SEG_OPTION_SELECTED, 1); | ||||
|   _segments[0].setOption(SEG_OPTION_ON, 1); | ||||
|   _segments[0].opacity = 255; | ||||
|   _segments[0].cct = 128; | ||||
| 
 | ||||
|   for (uint16_t i = 1; i < MAX_NUM_SEGMENTS; i++) | ||||
|   { | ||||
|  | @ -630,6 +642,7 @@ void WS2812FX::resetSegments() { | |||
|     _segments[i].grouping = 1; | ||||
|     _segments[i].setOption(SEG_OPTION_ON, 1); | ||||
|     _segments[i].opacity = 255; | ||||
|     _segments[i].cct = 128; | ||||
|     _segments[i].speed = DEFAULT_SPEED; | ||||
|     _segments[i].intensity = DEFAULT_INTENSITY; | ||||
|     _segment_runtimes[i].reset(); | ||||
|  |  | |||
|  | @ -10,6 +10,9 @@ | |||
| #include "bus_wrapper.h" | ||||
| #include <Arduino.h> | ||||
| 
 | ||||
| //color.cpp
 | ||||
| uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); | ||||
| 
 | ||||
| // enable additional debug output
 | ||||
| #ifdef WLED_DEBUG | ||||
|   #ifndef ESP8266 | ||||
|  | @ -65,79 +68,48 @@ struct BusConfig { | |||
| //parent class of BusDigital and BusPwm
 | ||||
| class Bus { | ||||
|   public: | ||||
|   Bus(uint8_t type, uint16_t start) { | ||||
|     _type = type; | ||||
|     _start = start; | ||||
|   }; | ||||
|    | ||||
|   virtual void show() {} | ||||
|   virtual bool canShow() { return true; } | ||||
|     Bus(uint8_t type, uint16_t start) { | ||||
|       _type = type; | ||||
|       _start = start; | ||||
|     }; | ||||
| 
 | ||||
|   virtual void setPixelColor(uint16_t pix, uint32_t c) {}; | ||||
|     virtual ~Bus() {} //throw the bus under the bus
 | ||||
| 
 | ||||
|   virtual void setBrightness(uint8_t b) {}; | ||||
|     virtual void     show() {} | ||||
|     virtual bool     canShow() { return true; } | ||||
|     virtual void     setPixelColor(uint16_t pix, uint32_t c) {}; | ||||
|     virtual void     setPixelColor(uint16_t pix, uint32_t c, uint8_t cct) {}; | ||||
|     virtual uint32_t getPixelColor(uint16_t pix) { return 0; }; | ||||
|     virtual void     setBrightness(uint8_t b) {}; | ||||
|     virtual void     cleanup() {}; | ||||
|     virtual uint8_t  getPins(uint8_t* pinArray) { return 0; } | ||||
|     virtual uint16_t getLength() { return 1; } | ||||
|     virtual void     setColorOrder() {} | ||||
|     virtual uint8_t  getColorOrder() { return COL_ORDER_RGB; } | ||||
|     virtual uint8_t  skippedLeds() { return 0; } | ||||
| 
 | ||||
|   virtual uint32_t getPixelColor(uint16_t pix) { return 0; }; | ||||
|     inline uint16_t  getStart() { return _start; } | ||||
|     inline void      setStart(uint16_t start) { _start = start; } | ||||
|     inline uint8_t   getType() { return _type; } | ||||
|     inline bool      isOk() { return _valid; } | ||||
|     inline bool      isOffRefreshRequired() { return _needsRefresh; } | ||||
|     inline bool      containsPixel(uint16_t pix) { return pix >= _start; } | ||||
| 
 | ||||
|   virtual void cleanup() {}; | ||||
|     virtual bool isRgbw() { return false; } | ||||
|     static  bool isRgbw(uint8_t type) { | ||||
|       if (type == TYPE_SK6812_RGBW || type == TYPE_TM1814) return true; | ||||
|       if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true; | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|   virtual ~Bus() { //throw the bus under the bus
 | ||||
|   } | ||||
| 
 | ||||
|   virtual uint8_t getPins(uint8_t* pinArray) { return 0; } | ||||
| 
 | ||||
|   inline uint16_t getStart() { | ||||
|     return _start; | ||||
|   } | ||||
| 
 | ||||
|   inline void setStart(uint16_t start) { | ||||
|     _start = start; | ||||
|   } | ||||
| 
 | ||||
|   virtual uint16_t getLength() { | ||||
|     return 1; | ||||
|   } | ||||
| 
 | ||||
|   virtual void setColorOrder() {} | ||||
| 
 | ||||
|   virtual uint8_t getColorOrder() { | ||||
|     return COL_ORDER_RGB; | ||||
|   } | ||||
| 
 | ||||
|   virtual bool isRgbw() { | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   virtual uint8_t skippedLeds() { | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
|   inline uint8_t getType() { | ||||
|     return _type; | ||||
|   } | ||||
| 
 | ||||
|   inline bool isOk() { | ||||
|     return _valid; | ||||
|   } | ||||
| 
 | ||||
|   static bool isRgbw(uint8_t type) { | ||||
|     if (type == TYPE_SK6812_RGBW || type == TYPE_TM1814) return true; | ||||
|     if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true; | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   inline bool isOffRefreshRequired() { | ||||
|     return _needsRefresh; | ||||
|   } | ||||
| 
 | ||||
|   bool reversed = false; | ||||
|     bool reversed = false; | ||||
| 
 | ||||
|   protected: | ||||
|   uint8_t _type = TYPE_NONE; | ||||
|   uint8_t _bri = 255; | ||||
|   uint16_t _start = 0; | ||||
|   bool _valid = false; | ||||
|   bool _needsRefresh = false; | ||||
|     uint8_t  _type = TYPE_NONE; | ||||
|     uint8_t  _bri = 255; | ||||
|     uint16_t _start = 0; | ||||
|     bool     _valid = false; | ||||
|     bool     _needsRefresh = false; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|  | @ -190,6 +162,11 @@ class BusDigital : public Bus { | |||
|     PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrder); | ||||
|   } | ||||
| 
 | ||||
|   void setPixelColor(uint16_t pix, uint32_t c, uint8_t cct) { | ||||
|     c = colorBalanceFromKelvin(2000+(cct<<5), c); // color correction from CCT
 | ||||
|     setPixelColor(pix, c); | ||||
|   } | ||||
| 
 | ||||
|   uint32_t getPixelColor(uint16_t pix) { | ||||
|     if (reversed) pix = _len - pix -1; | ||||
|     else pix += _skip; | ||||
|  | @ -285,6 +262,34 @@ class BusPwm : public Bus { | |||
|     _valid = true; | ||||
|   }; | ||||
| 
 | ||||
|   void setPixelColor(uint16_t pix, uint32_t c, uint8_t cct) { | ||||
|     if (pix != 0 || !_valid) return; //only react to first pixel
 | ||||
|     c = colorBalanceFromKelvin(2000+(cct<<5), c); // color correction from CCT (w remains unchanged)
 | ||||
|     uint8_t r = c >> 16; | ||||
|     uint8_t g = c >>  8; | ||||
|     uint8_t b = c      ; | ||||
|     uint8_t w = c >> 24; | ||||
| 
 | ||||
|     switch (_type) { | ||||
|       case TYPE_ANALOG_1CH: //one channel (white), use highest RGBW value
 | ||||
|         _data[0] = max(r, max(g, max(b, w))); | ||||
|         break; | ||||
|       case TYPE_ANALOG_2CH: //warm white + cold white
 | ||||
|         // perhaps a non-linear adjustment would be in order. need to test
 | ||||
|         _data[1] = (w * cct) / 255; | ||||
|         _data[0] = 255 - _data[1]; // or (w * (255-cct)) / 255;
 | ||||
|         break; | ||||
|       case TYPE_ANALOG_5CH: //RGB + warm white + cold white
 | ||||
|         // perhaps a non-linear adjustment would be in order. need to test
 | ||||
|         _data[4] = (w * cct) / 255; w = 255 - w; // or (w * (255-cct)) / 255;
 | ||||
|       case TYPE_ANALOG_4CH: //RGBW
 | ||||
|         _data[3] = w; | ||||
|       case TYPE_ANALOG_3CH: //standard dumb RGB
 | ||||
|         _data[0] = r; _data[1] = g; _data[2] = b; | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void setPixelColor(uint16_t pix, uint32_t c) { | ||||
|     if (pix != 0 || !_valid) return; //only react to first pixel
 | ||||
|     uint8_t r = c >> 16; | ||||
|  | @ -295,14 +300,11 @@ class BusPwm : public Bus { | |||
|     switch (_type) { | ||||
|       case TYPE_ANALOG_1CH: //one channel (white), use highest RGBW value
 | ||||
|         _data[0] = max(r, max(g, max(b, w))); break; | ||||
|        | ||||
|       case TYPE_ANALOG_2CH: //warm white + cold white, we'll need some nice handling here, for now just R+G channels
 | ||||
|       case TYPE_ANALOG_2CH: //warm white + cold white
 | ||||
|       case TYPE_ANALOG_3CH: //standard dumb RGB
 | ||||
|       case TYPE_ANALOG_4CH: //RGBW
 | ||||
|       case TYPE_ANALOG_4CH: //standard dumb RGBW
 | ||||
|       case TYPE_ANALOG_5CH: //we'll want the white handling from 2CH here + RGB
 | ||||
|         _data[0] = r; _data[1] = g; _data[2] = b; _data[3] = w; _data[4] = 0; break; | ||||
| 
 | ||||
|       default: return; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -417,6 +419,11 @@ class BusNetwork : public Bus { | |||
|     if (_rgbw) _data[offset+3] = 0xFF & (c >> 24); | ||||
|   } | ||||
| 
 | ||||
|   void setPixelColor(uint16_t pix, uint32_t c, uint8_t cct) { | ||||
|     c = colorBalanceFromKelvin(2000+(cct<<5), c); // color correction from CCT
 | ||||
|     setPixelColor(pix, c); | ||||
|   } | ||||
| 
 | ||||
|   uint32_t getPixelColor(uint16_t pix) { | ||||
|     if (!_valid || pix >= _len) return 0; | ||||
|     uint16_t offset = pix * _UDPchannels; | ||||
|  | @ -538,12 +545,13 @@ class BusManager { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void setPixelColor(uint16_t pix, uint32_t c) { | ||||
|   void setPixelColor(uint16_t pix, uint32_t c, int16_t cct=-1) { | ||||
|     for (uint8_t i = 0; i < numBusses; i++) { | ||||
|       Bus* b = busses[i]; | ||||
|       uint16_t bstart = b->getStart(); | ||||
|       if (pix < bstart || pix >= bstart + b->getLength()) continue; | ||||
|       busses[i]->setPixelColor(pix - bstart, c); | ||||
|       if (cct<0) busses[i]->setPixelColor(pix - bstart, c);       // no white balance
 | ||||
|       else       busses[i]->setPixelColor(pix - bstart, c, cct);  // do white balance
 | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
|  | @ -84,6 +84,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { | |||
|   CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]); | ||||
|   CJSON(strip.milliampsPerLed, hw_led[F("ledma")]); | ||||
|   CJSON(strip.rgbwMode, hw_led[F("rgbwm")]); | ||||
|   CJSON(allowCCT, hw_led["cct"]); | ||||
| 
 | ||||
|   JsonArray ins = hw_led["ins"]; | ||||
| 
 | ||||
|  | @ -530,6 +531,7 @@ void serializeConfig() { | |||
|   hw_led[F("maxpwr")] = strip.ablMilliampsMax; | ||||
|   hw_led[F("ledma")] = strip.milliampsPerLed; | ||||
|   hw_led[F("rgbwm")] = strip.rgbwMode; | ||||
|   hw_led["cct"] = allowCCT; | ||||
| 
 | ||||
|   JsonArray hw_led_ins = hw_led.createNestedArray("ins"); | ||||
| 
 | ||||
|  | @ -546,7 +548,7 @@ void serializeConfig() { | |||
|     ins[F("order")] = bus->getColorOrder(); | ||||
|     ins["rev"] = bus->reversed; | ||||
|     ins[F("skip")] = bus->skippedLeds(); | ||||
|     ins["type"] = bus->getType() & 0x7F;; | ||||
|     ins["type"] = bus->getType() & 0x7F; | ||||
|     ins["ref"] = bus->isOffRefreshRequired(); | ||||
|     ins[F("rgbw")] = bus->isRgbw(); | ||||
|   } | ||||
|  |  | |||
|  | @ -467,6 +467,22 @@ img { | |||
| 	z-index: -1; | ||||
| } | ||||
| 
 | ||||
| #rwrap .sliderdisplay, | ||||
| #gwrap .sliderdisplay, | ||||
| #bwrap .sliderdisplay, | ||||
| #wwrap .sliderdisplay, | ||||
| #wbal .sliderdisplay { | ||||
| 	height: 28px; | ||||
| 	top: 0; bottom: 0; | ||||
| 	left: 0; right: 0; | ||||
| 	/*border: 1px solid var(--c-b);*/ | ||||
| } | ||||
| #rwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #f00); } | ||||
| #gwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #0f0); } | ||||
| #bwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #00f); } | ||||
| #wwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #fff); } | ||||
| #wbal .sliderdisplay  { background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #d4e0ff); } | ||||
| 
 | ||||
| .sliderbubble { | ||||
|     width: 36px; | ||||
|     line-height: 24px; | ||||
|  | @ -492,6 +508,14 @@ input[type=range] { | |||
| 	background-color: transparent; | ||||
| 	cursor: pointer; | ||||
| } | ||||
| #rwrap input[type=range], | ||||
| #gwrap input[type=range], | ||||
| #bwrap input[type=range], | ||||
| #wwrap input[type=range], | ||||
| #wbal input[type=range] { | ||||
| 	width: 252px; | ||||
| 	margin: 0; | ||||
| } | ||||
| input[type=range]:focus { | ||||
| 	outline: none; | ||||
| } | ||||
|  | @ -527,8 +551,24 @@ input[type=range]:active + .sliderbubble { | |||
| 	display: inline; | ||||
| 	transform: translateX(-50%); | ||||
| } | ||||
| 
 | ||||
| #wwrap { | ||||
| #rwrap input[type=range]::-webkit-slider-thumb, | ||||
| #gwrap input[type=range]::-webkit-slider-thumb, | ||||
| #bwrap input[type=range]::-webkit-slider-thumb, | ||||
| #wwrap input[type=range]::-webkit-slider-thumb, | ||||
| #wbal input[type=range]::-webkit-slider-thumb { | ||||
| 	height: 18px; | ||||
| 	width: 18px; | ||||
| 	border: 2px solid #000; | ||||
| 	margin-top: 5px; | ||||
| } | ||||
| #rwrap input[type=range]::-moz-range-thumb, | ||||
| #gwrap input[type=range]::-moz-range-thumb, | ||||
| #bwrap input[type=range]::-moz-range-thumb, | ||||
| #wwrap input[type=range]::-moz-range-thumb, | ||||
| #wbal input[type=range]::-moz-range-thumb { | ||||
| 	border: 2px solid var(--c-1); | ||||
| } | ||||
| #wwrap, #wbal { | ||||
| 	display: none; | ||||
| } | ||||
| 
 | ||||
|  | @ -537,6 +577,14 @@ input[type=range]:active + .sliderbubble { | |||
| 	width: 240px; | ||||
| 	position: relative; | ||||
| } | ||||
| #rwrap .sliderwrap, | ||||
| #gwrap .sliderwrap, | ||||
| #bwrap .sliderwrap, | ||||
| #wwrap .sliderwrap, | ||||
| #wbal .sliderwrap { | ||||
| 	width: 260px; | ||||
| 	margin: 10px 0 0; | ||||
| } | ||||
| 
 | ||||
| .sbs { | ||||
| 	margin: 0px -20px 5px -6px; | ||||
|  |  | |||
|  | @ -47,22 +47,29 @@ | |||
| 		<div id="picker" class="noslide"></div> | ||||
| 		<div id="rgbwrap"> | ||||
| 			<div class="sliderwrap il"> | ||||
| 				<input id="sliderR" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,1)" max="255" min="0" type="range" value="128" /> | ||||
| 				<input id="sliderR" class="noslide" onchange="fromRgb()" max="255" min="0" type="range" value="128" /> | ||||
| 				<div class="sliderdisplay"></div> | ||||
| 			</div><br> | ||||
| 			<div class="sliderwrap il"> | ||||
| 				<input id="sliderG" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,2)" max="255" min="0" type="range" value="128" /> | ||||
| 				<input id="sliderG" class="noslide" onchange="fromRgb()" max="255" min="0" type="range" value="128" /> | ||||
| 				<div class="sliderdisplay"></div> | ||||
| 			</div><br> | ||||
| 			<div class="sliderwrap il"> | ||||
| 				<input id="sliderB" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,3)" max="255" min="0" type="range" value="128" /> | ||||
| 				<input id="sliderB" class="noslide" onchange="fromRgb()" max="255" min="0" type="range" value="128" /> | ||||
| 				<div class="sliderdisplay"></div> | ||||
| 			</div><br> | ||||
| 		</div> | ||||
| 		<div id="wwrap"> | ||||
| 			<p class="labels">White channel</p> | ||||
| 			<div class="sliderwrap il"> | ||||
| 				<input id="sliderW" class="noslide" onchange="setColor(0)" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" /> | ||||
| 				<input id="sliderW" class="noslide" onchange="setColor(0)" max="255" min="0" type="range" value="128" /> | ||||
| 				<div class="sliderdisplay"></div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		<div id="wbal"> | ||||
| 			<p class="labels">White balance</p> | ||||
| 			<div class="sliderwrap il"> | ||||
| 				<input id="sliderA" class="noslide" onchange="setBalance(this.value)" max="255" min="0" type="range" value="128" /> | ||||
| 				<div class="sliderdisplay"></div> | ||||
| 			</div> | ||||
| 		</div> | ||||
|  | @ -98,7 +105,7 @@ | |||
| 					<label class="check schkl"> | ||||
| 						  | ||||
| 						<input type="radio" value="${palettes[i].id}" name="palette" onChange="setPalette()"> | ||||
| 						<span class="checkmark schk"></span> | ||||
| 						<span class="radiomark schk"></span> | ||||
| 					</label> | ||||
| 					<div class="lstIcontent"> | ||||
| 						<span class="lstIname"> | ||||
|  |  | |||
|  | @ -51,7 +51,7 @@ var cpick = new iro.ColorPicker("#picker", { | |||
|       options: { | ||||
|         sliderType: 'value' | ||||
|       } | ||||
|     }, | ||||
|     }/*, | ||||
|     { | ||||
|       component: iro.ui.Slider, | ||||
|       options: { | ||||
|  | @ -59,7 +59,7 @@ var cpick = new iro.ColorPicker("#picker", { | |||
|         minTemperature: 2100, | ||||
|         maxTemperature: 10000 | ||||
|       } | ||||
|     } | ||||
|     }*/ | ||||
|   ] | ||||
| }); | ||||
| 
 | ||||
|  | @ -854,21 +854,14 @@ function loadNodes() | |||
| 	}); | ||||
| } | ||||
| 
 | ||||
| function updateTrail(e, slidercol) | ||||
| function updateTrail(e) | ||||
| { | ||||
| 	if (e==null) return; | ||||
| 	var max = e.hasAttribute('max') ? e.attributes.max.value : 255; | ||||
| 	var perc = e.value * 100 / max; | ||||
| 	perc = parseInt(perc); | ||||
|   if (perc < 50) perc += 2; | ||||
| 	var scol; | ||||
| 	switch (slidercol) { | ||||
| 	case 1: scol = "#f00"; break; | ||||
| 	case 2: scol = "#0f0"; break; | ||||
| 	case 3: scol = "#00f"; break; | ||||
| 	default: scol = "var(--c-f)"; | ||||
| 	} | ||||
| 	var val = `linear-gradient(90deg, ${scol} ${perc}%, var(--c-4) ${perc}%)`; | ||||
| 	var val = `linear-gradient(90deg, var(--c-f) ${perc}%, var(--c-4) ${perc}%)`; | ||||
| 	e.parentNode.getElementsByClassName('sliderdisplay')[0].style.background = val; | ||||
| } | ||||
| 
 | ||||
|  | @ -939,8 +932,8 @@ function updateUI() | |||
| 	updateTrail(d.getElementById('sliderBri')); | ||||
| 	updateTrail(d.getElementById('sliderSpeed')); | ||||
| 	updateTrail(d.getElementById('sliderIntensity')); | ||||
| 	updateTrail(d.getElementById('sliderW')); | ||||
| 	if (isRgbw) d.getElementById('wwrap').style.display = "block"; | ||||
| 	d.getElementById('wwrap').style.display = (isRgbw) ? "block":"none"; | ||||
| 	d.getElementById("wbal").style.display = (lastinfo.leds.cct) ? "block":"none"; | ||||
| 
 | ||||
| 	updatePA(); | ||||
| 	updateHex(); | ||||
|  | @ -1023,6 +1016,7 @@ function readState(s,command=false) { | |||
|     selectSlot(csel); | ||||
|   } | ||||
|   d.getElementById('sliderW').value = whites[csel]; | ||||
|   if (i.cct && i.cct>=0) d.getElementById("sliderA").value = i.cct; | ||||
| 
 | ||||
|   d.getElementById('sliderSpeed').value = i.sx; | ||||
|   d.getElementById('sliderIntensity').value = i.ix; | ||||
|  | @ -1560,6 +1554,11 @@ function setSegBri(s){ | |||
| 	requestJson(obj); | ||||
| } | ||||
| 
 | ||||
| function setBalance(b) | ||||
| { | ||||
| 	var obj = {"seg": {"cct": parseInt(b)}}; | ||||
| 	requestJson(obj); | ||||
| } | ||||
| function setX(ind = null) { | ||||
| 	if (ind === null) { | ||||
| 		ind = parseInt(d.querySelector('#fxlist input[name="fx"]:checked').value); | ||||
|  | @ -1723,7 +1722,6 @@ function selectSlot(b) { | |||
| 	cd[csel].style.width="50px"; | ||||
| 	cpick.color.set(cd[csel].style.backgroundColor); | ||||
| 	d.getElementById('sliderW').value = whites[csel]; | ||||
| 	updateTrail(d.getElementById('sliderW')); | ||||
| 	updateHex(); | ||||
| 	updateRgb(); | ||||
| 	redrawPalPrev(); | ||||
|  | @ -1748,12 +1746,9 @@ function pC(col) | |||
| function updateRgb() | ||||
| { | ||||
| 	var col = cpick.color.rgb; | ||||
| 	var s = d.getElementById('sliderR'); | ||||
| 	s.value = col.r; updateTrail(s,1); | ||||
| 	s = d.getElementById('sliderG'); | ||||
| 	s.value = col.g; updateTrail(s,2); | ||||
| 	s = d.getElementById('sliderB'); | ||||
| 	s.value = col.b; updateTrail(s,3); | ||||
| 	d.getElementById('sliderR').value = col.r; | ||||
| 	d.getElementById('sliderG').value = col.g; | ||||
| 	d.getElementById('sliderB').value = col.b; | ||||
| } | ||||
| 
 | ||||
| function updateHex() | ||||
|  |  | |||
|  | @ -247,8 +247,8 @@ | |||
|       gId('m0').innerHTML = memu; | ||||
|       bquot = memu / maxM * 100; | ||||
|       gId('dbar').style.background = `linear-gradient(90deg, ${bquot > 60 ? (bquot > 90 ? "red":"orange"):"#ccc"} 0 ${bquot}%%, #444 ${bquot}%% 100%%)`; | ||||
|       gId('ledwarning').style.display = (sLC > maxPB || maxLC > 800 || bquot > 80) ? 'inline':'none'; | ||||
|       gId('ledwarning').style.color = (sLC > maxPB || maxLC > maxPB || bquot > 100) ? 'red':'orange'; | ||||
|       gId('ledwarning').style.display = (maxLC > Math.min(maxPB,800) || bquot > 80) ? 'inline':'none'; | ||||
|       gId('ledwarning').style.color = (maxLC > Math.max(maxPB,800) || bquot > 100) ? 'red':'orange'; | ||||
|       gId('wreason').innerHTML = (bquot > 80) ? "80% of max. LED memory" +(bquot>100 ? ` (<b>ERROR: Using over ${maxM}B!</b>)` : "") : "800 LEDs per output"; | ||||
|       // calculate power | ||||
|       var val = Math.ceil((100 + sPC * laprev)/500)/2; | ||||
|  | @ -389,11 +389,71 @@ ${i+1}: | |||
|       req.send(formData); | ||||
|       d.Sf.data.value = ''; | ||||
|       return false; | ||||
|     } | ||||
|     // https://stackoverflow.com/questions/7346563/loading-local-json-file | ||||
|     function loadCfg(o) { | ||||
|       var f, fr; | ||||
| 
 | ||||
|       if (typeof window.FileReader !== 'function') { | ||||
|         alert("The file API isn't supported on this browser yet."); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       if (!o.files) { | ||||
|         alert("This browser doesn't seem to support the `files` property of file inputs."); | ||||
|       } else if (!o.files[0]) { | ||||
|         alert("Please select a JSON file before clicking 'Apply'"); | ||||
|       } else { | ||||
|         f = o.files[0]; | ||||
|         fr = new FileReader(); | ||||
|         fr.onload = receivedText; | ||||
|         fr.readAsText(f); | ||||
|       } | ||||
|       o.value = ''; | ||||
| 
 | ||||
|       function receivedText(e) { | ||||
|         let lines = e.target.result; | ||||
|         var c = JSON.parse(lines);  | ||||
|         if (c.hw) { | ||||
|           if (c.hw.led) { | ||||
|             for (var i=0; i<10; i++) addLEDs(-1); | ||||
|             var l = c.hw.led; | ||||
|             l.ins.forEach((v,i,a)=>{ | ||||
|               addLEDs(1); | ||||
|               for (var j=0; j<v.pin.length; j++) d.getElementsByName(`L${j}${i}`)[0].value = v.pin[j]; | ||||
|               d.getElementsByName("LT"+i)[0].value = v.type; | ||||
|               d.getElementsByName("LS"+i)[0].value = v.start; | ||||
|               d.getElementsByName("LC"+i)[0].value = v.len; | ||||
|               d.getElementsByName("CO"+i)[0].value = v.order; | ||||
|               d.getElementsByName("SL"+i)[0].checked = v.skip; | ||||
|               d.getElementsByName("RF"+i)[0].checked = v.ref; | ||||
|               d.getElementsByName("CV"+i)[0].checked = v.rev; | ||||
|             }); | ||||
|           } | ||||
|           if (c.hw.btn) { | ||||
|             var b = c.hw.btn; | ||||
|             if (Array.isArray(b.ins)) gId("btns").innerHTML = ""; | ||||
|             b.ins.forEach((v,i,a)=>{ | ||||
|               addBtn(i,v.pin[0],v.type); | ||||
|             }); | ||||
|             d.getElementsByName("TT")[0].value = b.tt; | ||||
|           } | ||||
|           if (c.hw.ir) { | ||||
|             d.getElementsByName("IR")[0].value = c.hw.ir.pin; | ||||
|             d.getElementsByName("IT")[0].value = c.hw.ir.type; | ||||
|           } | ||||
|           if (c.hw.relay) { | ||||
|             d.getElementsByName("RL")[0].value = c.hw.relay.pin; | ||||
|             d.getElementsByName("RM")[0].checked = c.hw.relay.inv; | ||||
|           } | ||||
|           UI(); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 		function GetV() | ||||
| 		{ | ||||
|       //values injected by server while sending HTML | ||||
|       //d.um_p=[6,7,8,9,10,11,1];bLimits(3,4096,4000,1664);d.Sf.MS.checked=1;addLEDs(1);d.Sf.L00.value=2;d.Sf.LC0.value=30;d.Sf.LT0.value=22;d.Sf.CO0.value=0;d.Sf.LS0.value=15;d.Sf.CV0.checked=1;d.Sf.SL0.checked=0;addLEDs(1);d.Sf.L01.value=10;d.Sf.L11.value=10;d.Sf.L21.value=1;d.Sf.L31.value=10;d.Sf.LC1.value=60;d.Sf.LT1.value=80;d.Sf.CO1.value=1;d.Sf.LS1.value=0;d.Sf.CV1.checked=0;d.Sf.SL1.checked=0;d.Sf.MA.value=850;d.Sf.LA.value=0;d.Sf.CA.value=56;d.Sf.AW.value=3;d.Sf.BO.checked=1;d.Sf.BP.value=80;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=0;d.Sf.BF.value=100;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=0;d.Sf.PB.selectedIndex=0;d.Sf.RL.value=12;d.Sf.RM.checked=1;addBtn(0,0,0);addBtn(1,-1,0);d.Sf.TT.value=32;d.Sf.IR.value=-1;d.Sf.IT.value=0; | ||||
|       //d.um_p=[6,7,8,9,10,11,14,15,13,1,21,19,22,25,26,27,5,23,18,17];bLimits(10,2048,64000,8192);d.Sf.MS.checked=1;d.Sf.CCT.checked=0;addLEDs(1);d.Sf.L00.value=192;d.Sf.L10.value=168;d.Sf.L20.value=0;d.Sf.L30.value=61;d.Sf.LC0.value=421;d.Sf.LT0.value=80;d.Sf.CO0.value=1;d.Sf.LS0.value=0;d.Sf.CV0.checked=0;d.Sf.SL0.checked=0;d.Sf.RF0.checked=0;d.Sf.MA.value=850;d.Sf.LA.value=0;d.Sf.CA.value=127;d.Sf.AW.value=3;d.Sf.BO.checked=0;d.Sf.BP.value=0;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=1;d.Sf.BF.value=100;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=1;d.Sf.PB.selectedIndex=0;d.Sf.RL.value=-1;d.Sf.RM.checked=1;addBtn(0,-1,0);addBtn(1,-1,0);addBtn(2,-1,0);addBtn(3,-1,0);d.Sf.TT.value=32;d.Sf.IR.value=-1;d.Sf.IT.value=8; | ||||
|     } | ||||
| 	</script> | ||||
| 	<style> | ||||
|  | @ -448,6 +508,7 @@ ${i+1}: | |||
|     <hr style="width:260px"> | ||||
|     Make a segment for each output: <input type="checkbox" name="MS"> <br> | ||||
|     Custom bus start indices: <input type="checkbox" onchange="tglSi(this.checked)" id="si"> <br> | ||||
|     Allow WB correction:  <input type="checkbox" name="CCT"> <br> | ||||
|     <hr style="width:260px"> | ||||
|     <div id="btns"></div> | ||||
|     Touch threshold: <input type="number" class="s" min="0" max="100" name="TT" required><br> | ||||
|  | @ -506,7 +567,10 @@ ${i+1}: | |||
|         <option value=3>Dual</option> | ||||
|         <option value=4>Legacy</option> | ||||
|       </select> | ||||
|     <br></span><hr> | ||||
|     <br></span> | ||||
|     <hr style="width:260px"> | ||||
|     <div id="cfg">Config template: <input type="file" name="data2" accept=".json"> <input type="button" value="Apply" onclick="loadCfg(d.Sf.data2);"><br></div> | ||||
|     <hr> | ||||
|     <button type="button" onclick="B()">Back</button><button type="submit">Save</button> | ||||
| 	</form> | ||||
| </body> | ||||
|  |  | |||
|  | @ -95,6 +95,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) | |||
|     uint8_t pins[5] = {255, 255, 255, 255, 255}; | ||||
| 
 | ||||
|     autoSegments = request->hasArg(F("MS")); | ||||
|     allowCCT = request->hasArg(F("CCT")); | ||||
| 
 | ||||
|     for (uint8_t s = 0; s < WLED_MAX_BUSSES; s++) { | ||||
|       char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin
 | ||||
|  |  | |||
|  | @ -270,6 +270,7 @@ WLED_GLOBAL byte bootPreset   _INIT(0);                   // save preset to load | |||
| //if false, only one segment spanning the total LEDs is created,
 | ||||
| //but not on LED settings save if there is more than one segment currently
 | ||||
| WLED_GLOBAL bool autoSegments _INIT(false); | ||||
| WLED_GLOBAL bool allowCCT _INIT(false);           //CCT color correction
 | ||||
| 
 | ||||
| WLED_GLOBAL byte col[]    _INIT_N(({ 255, 160, 0, 0 }));  // current RGB(W) primary color. col[] should be updated if you want to change the color.
 | ||||
| WLED_GLOBAL byte colSec[] _INIT_N(({ 0, 0, 0, 0 }));      // current RGB(W) secondary color
 | ||||
|  | @ -508,7 +509,6 @@ WLED_GLOBAL byte timerWeekday[] _INIT_N(({ 255, 255, 255, 255, 255, 255, 255, 25 | |||
| WLED_GLOBAL bool blynkEnabled _INIT(false); | ||||
| 
 | ||||
| //playlists
 | ||||
| WLED_GLOBAL unsigned long presetCycledTime _INIT(0); | ||||
| WLED_GLOBAL int16_t currentPlaylist _INIT(-1); | ||||
| //still used for "PL=~" HTTP API command
 | ||||
| WLED_GLOBAL byte presetCycCurr _INIT(0); | ||||
|  | @ -637,10 +637,9 @@ WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager()); | |||
| #define WLED_WIFI_CONFIGURED (strlen(clientSSID) >= 1 && strcmp(clientSSID, DEFAULT_CLIENT_SSID) != 0) | ||||
| #define WLED_MQTT_CONNECTED (mqtt != nullptr && mqtt->connected()) | ||||
| 
 | ||||
| // append new c string to temp buffer efficiently
 | ||||
| bool oappend(const char* txt); | ||||
| // append new number to temp buffer efficiently
 | ||||
| bool oappendi(int i); | ||||
| //macro to convert F to const
 | ||||
| #define SET_F(x)  (const char*)F(x) | ||||
| 
 | ||||
| 
 | ||||
| class WLED { | ||||
| public: | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 Blaz Kristan
						Blaz Kristan