32_WifiLight.pm 204 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242
  1. ##############################################
  2. # $Id: 32_WifiLight.pm 15907 2018-01-16 20:58:44Z herrmannj $
  3. # TODO
  4. # versions
  5. # 00 POC
  6. # ..
  7. # 50 Stable
  8. # 51 new milight color converter
  9. # 52 timing for transitions: drop frames if required
  10. # 53 transition names and events
  11. # 54 drop frames ll add-on / lock ll queue
  12. # 55 add ll queue lock count
  13. # 56 RGB in
  14. # 57 bridge v2
  15. # 58 gamma correction
  16. # 59 fix "off" with ramp
  17. # 60 add dimup/dimdown
  18. # 61 introduce dimSteps
  19. # 62 introduce defaultColor
  20. # 63 LW12 define if lw12 is unavailable at startup
  21. # 64 transition with ramp 0 fixed
  22. # 65 some typos with impact to RGBW1 and RGBW2
  23. # 66 readings: lower camelCase and limited trigger
  24. # 67 restore state after startup
  25. # 68 LW12 reconnect after timeout
  26. # 69 RGBW1 timing improved
  27. # 70 colorpicker
  28. # 71 default ramp attrib
  29. # 72 add LD316
  30. # 73 add LD382
  31. # 74 add color calibration (hue intersections) for RGB type controller
  32. # 75 add white point adjustment for RGB type controller
  33. # 76 add LW12 HX001
  34. # 77 milight RGBW2: critical cmds sendout repeatly
  35. # 78 add attrib for color managment (rgb types)
  36. # 79 add LD382 RGB ony mode
  37. # 80 HSV2fourChannel bug fixed (thnx to lexorius)
  38. # 81 LW12FC added
  39. # 82 LD382A (FW 1.0.6)
  40. # 83 fixed ramp handling (thnx to henryk)
  41. # 84 sengled boost added (thnx to scooty)
  42. # 85 milight white, improved reliability
  43. # 86 milight white, improved reliability / mark II
  44. # 87 milight rgbw2, dim bug
  45. # 88 readingFnAttributes
  46. # 89 add LD316A
  47. # 90 Sunricher poc
  48. # 91 milight colorcast fixed, more robust tcp re-connect
  49. # verbose level
  50. # 0: quit
  51. # 1: error
  52. # 2: warning
  53. # 3: user command
  54. # 4: 1st technical level (detailed internal reporting)
  55. # 5: 2nd technical level (full internal reporting)
  56. package main;
  57. use strict;
  58. use warnings;
  59. use IO::Handle;
  60. use IO::Socket;
  61. use IO::Select;
  62. use Time::HiRes;
  63. use Data::Dumper;
  64. use Color;
  65. sub
  66. WifiLight_Initialize(@)
  67. {
  68. my ($hash) = @_;
  69. FHEM_colorpickerInit();
  70. $hash->{DefFn} = "WifiLight_Define";
  71. $hash->{UndefFn} = "WifiLight_Undef";
  72. $hash->{ShutdownFn} = "WifiLight_Undef";
  73. $hash->{SetFn} = "WifiLight_Set";
  74. $hash->{GetFn} = "WifiLight_Get";
  75. $hash->{AttrFn} = "WifiLight_Attr";
  76. $hash->{NotifyFn} = "WifiLight_Notify";
  77. $hash->{AttrList} = "gamma dimStep defaultColor defaultRamp colorCast whitePoint"
  78. ." $readingFnAttributes";
  79. return undef;
  80. }
  81. sub
  82. WifiLight_Define($$)
  83. {
  84. my ($hash, $def) = @_;
  85. my @a = split("[ \t][ \t]*", $def);
  86. my $name = $a[0];
  87. my $key;
  88. return "wrong syntax: define <name> WifiLight <type> <connection>" if(@a != 4);
  89. # return "unknown LED type ($a[2]): choose one of RGB, RGBW, RGBW1, RGBW2, White" unless (grep /$a[2]/, ('RGB', 'RGBW', 'RGBW1', 'RGBW2', 'White'));
  90. $hash->{LEDTYPE} = $a[2];
  91. my $otherLights;
  92. if ($a[3] =~ m/(bridge-V2):([^:]+):*(\d+)*/g)
  93. {
  94. $hash->{CONNECTION} = $1;
  95. $hash->{IP} = $2;
  96. $hash->{PORT} = $3?$3:50000;
  97. $hash->{PROTO} = 0;
  98. #my @hlCmdQueue = [];
  99. @{$hash->{helper}->{hlCmdQueue}} = (); #\@hlCmdQueue;
  100. # $hash->{SERVICE} = 48899; unkown for v2
  101. # search if this bridge is already defined
  102. # if so, we need a shared buffer (llCmdQueue), shared socket and we need to check if the requied slot is free
  103. foreach $key (keys %defs)
  104. {
  105. if (($defs{$key}{TYPE} eq 'WifiLight') && ($defs{$key}{IP} eq $hash->{IP}) && ($key ne $name))
  106. {
  107. #bridge is in use
  108. Log3 (undef, 3, "WifiLight: requested bridge $hash->{CONNECTION} at $hash->{IP} already in use by $key, copy llCmdQueue");
  109. $hash->{helper}->{llCmdQueue} = $defs{$key}{helper}{llCmdQueue};
  110. $hash->{helper}->{llLock} = 0;
  111. $hash->{helper}->{SOCKET} = $defs{$key}{helper}{SOCKET};
  112. $hash->{helper}->{SELECT} = $defs{$key}{helper}{SELECT};
  113. my $slotInUse = $defs{$key}{SLOT};
  114. $otherLights->{$slotInUse} = $defs{$key};
  115. }
  116. }
  117. if (!defined($hash->{helper}->{SOCKET}))
  118. {
  119. my $sock = IO::Socket::INET-> new (
  120. PeerPort => 48899,
  121. Blocking => 0,
  122. Proto => 'udp',
  123. Broadcast => 1) or return "can't bind: $@";
  124. my $select = IO::Select->new($sock);
  125. $hash->{helper}->{SOCKET} = $sock;
  126. $hash->{helper}->{SELECT} = $select;
  127. @{$hash->{helper}->{llCmdQueue}} = {};
  128. $hash->{helper}->{llLock} = 0;
  129. }
  130. }
  131. if ($a[3] =~ m/(bridge-V3):([^:]+):*(\d+)*/g)
  132. {
  133. $hash->{CONNECTION} = $1;
  134. $hash->{IP} = $2;
  135. $hash->{PORT} = $3?$3:8899;
  136. $hash->{PROTO} = 0;
  137. #my @hlCmdQueue = [];
  138. @{$hash->{helper}->{hlCmdQueue}} = (); #\@hlCmdQueue;
  139. # $hash->{SERVICE} = 48899;
  140. # search if this bridge is already defined
  141. # if so, we need a shared buffer (llCmdQueue), shared socket and we need to check if the requied slot is free
  142. foreach $key (keys %defs)
  143. {
  144. if (($defs{$key}{TYPE} eq 'WifiLight') && ($defs{$key}{IP} eq $hash->{IP}) && ($defs{$key}{PORT} eq $hash->{PORT}) && ($key ne $name))
  145. {
  146. #bridge is in use
  147. Log3 (undef, 3, "WifiLight: requested bridge $hash->{CONNECTION} at $hash->{IP} already in use by $key, copy llCmdQueue");
  148. $hash->{helper}->{llCmdQueue} = $defs{$key}{helper}{llCmdQueue};
  149. $hash->{helper}->{llLock} = 0;
  150. $hash->{helper}->{SOCKET} = $defs{$key}{helper}{SOCKET};
  151. $hash->{helper}->{SELECT} = $defs{$key}{helper}{SELECT};
  152. my $slotInUse = $defs{$key}{SLOT};
  153. $otherLights->{$slotInUse} = $defs{$key};
  154. }
  155. }
  156. if (!defined($hash->{helper}->{SOCKET}))
  157. {
  158. my $sock = IO::Socket::INET-> new (
  159. PeerPort => 48899,
  160. Blocking => 0,
  161. Proto => 'udp',
  162. Broadcast => 1) or return "can't bind: $@";
  163. my $select = IO::Select->new($sock);
  164. $hash->{helper}->{SOCKET} = $sock;
  165. $hash->{helper}->{SELECT} = $select;
  166. @{$hash->{helper}->{llCmdQueue}} = ();
  167. $hash->{helper}->{llLock} = 0;
  168. }
  169. }
  170. if ($a[3] =~ m/(LW12):([^:]+):*(\d+)*/g)
  171. {
  172. return "only RGB supported by LW12" if ($a[2] ne "RGB");
  173. $hash->{CONNECTION} = $1;
  174. $hash->{IP} = $2;
  175. $hash->{PORT} = $3?$3:5577;
  176. $hash->{PROTO} = 1;
  177. #$hash->{SERVICE} = 48899;
  178. $hash->{SLOT} = 0;
  179. @{$hash->{helper}->{hlCmdQueue}} = ();
  180. if (!defined($hash->{helper}->{SOCKET}))
  181. {
  182. my $sock = IO::Socket::INET-> new (
  183. PeerPort => $hash->{PORT},
  184. PeerAddr => $hash->{IP},
  185. Timeout => 1,
  186. Blocking => 0,
  187. Proto => 'tcp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
  188. my $select = IO::Select->new($sock);
  189. $hash->{helper}->{SOCKET} = $sock;
  190. $hash->{helper}->{SELECT} = $select;
  191. @{$hash->{helper}->{llCmdQueue}} = ();
  192. $hash->{helper}->{llLock} = 0;
  193. }
  194. }
  195. if ($a[3] =~ m/(LW12HX):([^:]+):*(\d+)*/g)
  196. {
  197. return "only RGB supported by LW12HX" if ($a[2] ne "RGB");
  198. $hash->{CONNECTION} = $1;
  199. $hash->{IP} = $2;
  200. $hash->{PORT} = $3?$3:5000;
  201. $hash->{PROTO} = 1;
  202. #$hash->{SERVICE} = 48899;
  203. $hash->{SLOT} = 0;
  204. @{$hash->{helper}->{hlCmdQueue}} = ();
  205. if (!defined($hash->{helper}->{SOCKET}))
  206. {
  207. my $sock = IO::Socket::INET-> new (
  208. PeerPort => $hash->{PORT},
  209. PeerAddr => $hash->{IP},
  210. Timeout => 1,
  211. Blocking => 0,
  212. Proto => 'tcp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
  213. my $select = IO::Select->new($sock);
  214. $hash->{helper}->{SOCKET} = $sock;
  215. $hash->{helper}->{SELECT} = $select;
  216. @{$hash->{helper}->{llCmdQueue}} = ();
  217. $hash->{helper}->{llLock} = 0;
  218. }
  219. }
  220. if ($a[3] =~ m/(LW12FC):([^:]+):*(\d+)*/g)
  221. {
  222. return "only RGB supported by LW12FC" if ($a[2] ne "RGB");
  223. $hash->{CONNECTION} = $1;
  224. $hash->{IP} = $2;
  225. $hash->{PORT} = $3?$3:5000;
  226. #$hash->{PROTO} = 1;
  227. #$hash->{SERVICE} = 48899;
  228. $hash->{SLOT} = 0;
  229. @{$hash->{helper}->{hlCmdQueue}} = ();
  230. if (!defined($hash->{helper}->{SOCKET}))
  231. {
  232. my $sock = IO::Socket::INET-> new (
  233. PeerPort => $hash->{PORT},
  234. PeerAddr => $hash->{IP},
  235. Blocking => 0,
  236. Proto => 'udp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
  237. my $select = IO::Select->new($sock);
  238. $hash->{helper}->{SOCKET} = $sock;
  239. $hash->{helper}->{SELECT} = $select;
  240. @{$hash->{helper}->{llCmdQueue}} = ();
  241. $hash->{helper}->{llLock} = 0;
  242. }
  243. }
  244. if ($a[3] =~ m/(LD316):([^:]+):*(\d+)*/g)
  245. {
  246. return "only RGBW supported by LD316" if ($a[2] ne "RGBW");
  247. $hash->{CONNECTION} = $1;
  248. $hash->{IP} = $2;
  249. $hash->{PORT} = $3?$3:5577;
  250. $hash->{PROTO} = 1;
  251. $hash->{SLOT} = 0;
  252. @{$hash->{helper}->{hlCmdQueue}} = ();
  253. if (!defined($hash->{helper}->{SOCKET}))
  254. {
  255. my $sock = IO::Socket::INET-> new (
  256. PeerPort => $hash->{PORT},
  257. PeerAddr => $hash->{IP},
  258. Timeout => 1,
  259. Blocking => 0,
  260. Proto => 'tcp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
  261. my $select = IO::Select->new($sock);
  262. $hash->{helper}->{SOCKET} = $sock;
  263. $hash->{helper}->{SELECT} = $select;
  264. @{$hash->{helper}->{llCmdQueue}} = ();
  265. $hash->{helper}->{llLock} = 0;
  266. }
  267. }
  268. if ($a[3] =~ m/(LD316A):([^:]+):*(\d+)*/g)
  269. {
  270. return "only RGBW supported by LD316A" if ($a[2] ne "RGBW");
  271. $hash->{CONNECTION} = $1;
  272. $hash->{IP} = $2;
  273. $hash->{PORT} = $3?$3:5577;
  274. $hash->{PROTO} = 1;
  275. $hash->{SLOT} = 0;
  276. @{$hash->{helper}->{hlCmdQueue}} = ();
  277. if (!defined($hash->{helper}->{SOCKET}))
  278. {
  279. my $sock = IO::Socket::INET-> new (
  280. PeerPort => $hash->{PORT},
  281. PeerAddr => $hash->{IP},
  282. Timeout => 1,
  283. Blocking => 0,
  284. Proto => 'tcp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
  285. my $select = IO::Select->new($sock);
  286. $hash->{helper}->{SOCKET} = $sock;
  287. $hash->{helper}->{SELECT} = $select;
  288. @{$hash->{helper}->{llCmdQueue}} = ();
  289. $hash->{helper}->{llLock} = 0;
  290. }
  291. }
  292. if ($a[3] =~ m/(LD382):([^:]+):*(\d+)*/g)
  293. {
  294. return "only RGB and RGBW supported by LD382" if (($a[2] ne "RGB") && ($a[2] ne "RGBW"));
  295. $hash->{CONNECTION} = $1;
  296. $hash->{IP} = $2;
  297. $hash->{PORT} = $3?$3:5577;
  298. $hash->{PROTO} = 1;
  299. #$hash->{SERVICE} = 48899;
  300. $hash->{SLOT} = 0;
  301. @{$hash->{helper}->{hlCmdQueue}} = ();
  302. if (!defined($hash->{helper}->{SOCKET}))
  303. {
  304. my $sock = IO::Socket::INET-> new (
  305. PeerPort => $hash->{PORT},
  306. PeerAddr => $hash->{IP},
  307. Timeout => 1,
  308. Blocking => 0,
  309. Proto => 'tcp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
  310. my $select = IO::Select->new($sock);
  311. $hash->{helper}->{SOCKET} = $sock;
  312. $hash->{helper}->{SELECT} = $select;
  313. @{$hash->{helper}->{llCmdQueue}} = ();
  314. $hash->{helper}->{llLock} = 0;
  315. }
  316. }
  317. if ($a[3] =~ m/(LD382A):([^:]+):*(\d+)*/g)
  318. {
  319. return "only RGB and RGBW supported by LD382A" if (($a[2] ne "RGB") && ($a[2] ne "RGBW"));
  320. $hash->{CONNECTION} = $1;
  321. $hash->{IP} = $2;
  322. $hash->{PORT} = $3?$3:5577;
  323. $hash->{PROTO} = 1;
  324. #$hash->{SERVICE} = 48899;
  325. $hash->{SLOT} = 0;
  326. @{$hash->{helper}->{hlCmdQueue}} = ();
  327. if (!defined($hash->{helper}->{SOCKET}))
  328. {
  329. my $sock = IO::Socket::INET-> new (
  330. PeerPort => $hash->{PORT},
  331. PeerAddr => $hash->{IP},
  332. Timeout => 1,
  333. Blocking => 0,
  334. Proto => 'tcp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
  335. my $select = IO::Select->new($sock);
  336. $hash->{helper}->{SOCKET} = $sock;
  337. $hash->{helper}->{SELECT} = $select;
  338. @{$hash->{helper}->{llCmdQueue}} = ();
  339. $hash->{helper}->{llLock} = 0;
  340. }
  341. }
  342. if ($a[3] =~ m/(SENGLED):([^:]+):*(\d+)*/g)
  343. {
  344. return "only White supported by SENGLED" if ($a[2] ne "White");
  345. $hash->{CONNECTION} = $1;
  346. $hash->{IP} = $2;
  347. $hash->{PORT} = $3?$3:9060;
  348. @{$hash->{helper}->{hlCmdQueue}} = ();
  349. if (!defined($hash->{helper}->{SOCKET}))
  350. {
  351. my $sock = IO::Socket::INET-> new (
  352. PeerPort => $hash->{PORT},
  353. PeerAddr => $hash->{IP},
  354. Blocking => 0,
  355. Proto => 'udp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
  356. my $select = IO::Select->new($sock);
  357. $hash->{helper}->{SOCKET} = $sock;
  358. $hash->{helper}->{SELECT} = $select;
  359. @{$hash->{helper}->{llCmdQueue}} = ();
  360. $hash->{helper}->{llLock} = 0;
  361. }
  362. }
  363. if ($a[3] =~ m/(SUNRICHER):([^:]+):*(\d+)*/gi)
  364. {
  365. # return "only White, DualWhite, RGB, RGBW supported by Sunricher" if ($a[2] ne 'RGBW');
  366. $hash->{CONNECTION} = uc $1;
  367. $hash->{IP} = $2;
  368. $hash->{PORT} = $3?$3:8899;
  369. $hash->{PROTO} = 1;
  370. $hash->{SLOT} = 0;
  371. @{$hash->{helper}->{hlCmdQueue}} = ();
  372. @{$hash->{helper}->{llCmdQueue}} = ();
  373. $hash->{helper}->{llLock} = 0;
  374. if (!defined($hash->{helper}->{SOCKET}))
  375. {
  376. my $sock = IO::Socket::INET-> new (
  377. PeerPort => $hash->{PORT},
  378. PeerAddr => $hash->{IP},
  379. Timeout => 1,
  380. Blocking => 0,
  381. Proto => 'tcp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
  382. my $select = IO::Select->new($sock);
  383. $hash->{helper}->{SOCKET} = $sock;
  384. $hash->{helper}->{SELECT} = $select;
  385. }
  386. }
  387. if ($a[3] =~ m/(SUNRICHERA):([^:]+):*(\d+)*/gi)
  388. {
  389. # return "only White, DualWhite, RGB, RGBW supported by Sunricher" if ($a[2] ne 'RGBW');
  390. $hash->{CONNECTION} = uc $1;
  391. $hash->{IP} = $2;
  392. $hash->{PORT} = $3?$3:8899;
  393. $hash->{PROTO} = 1;
  394. $hash->{SLOT} = 0;
  395. @{$hash->{helper}->{hlCmdQueue}} = ();
  396. if (!defined($hash->{helper}->{SOCKET}))
  397. {
  398. my $sock = IO::Socket::INET-> new (
  399. PeerPort => $hash->{PORT},
  400. PeerAddr => $hash->{IP},
  401. Timeout => 1,
  402. Blocking => 0,
  403. Proto => 'tcp') or Log3 ($hash, 3, "define $hash->{NAME}: can't reach ($@)");
  404. my $select = IO::Select->new($sock);
  405. $hash->{helper}->{SOCKET} = $sock;
  406. $hash->{helper}->{SELECT} = $select;
  407. @{$hash->{helper}->{llCmdQueue}} = ();
  408. $hash->{helper}->{llLock} = 0;
  409. }
  410. }
  411. return "unknown connection type, see documentation" if !(defined($hash->{CONNECTION}));
  412. Log3 ($hash, 4, "define $a[0] $a[1] $a[2] $a[3]");
  413. if (($hash->{LEDTYPE} eq 'RGB') && ($hash->{CONNECTION} =~ 'LW12'))
  414. {
  415. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65);
  416. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
  417. # color cast defaults in r,y, g, c, b, m: +/-30°
  418. my $cc = '0, -20, -20, -25, 0, -10';
  419. $attr{$name}{"colorCast"} = $cc;
  420. WifiLight_RGB_ColorConverter($hash, split(',', $cc));
  421. # white point defaults in r,g,b
  422. $attr{$name}{"whitePoint"} = '1, 0.75, 0.25';
  423. return undef;
  424. }
  425. if (($hash->{LEDTYPE} eq 'RGB') && ($hash->{CONNECTION} =~ 'LW12HX'))
  426. {
  427. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65);
  428. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
  429. # color cast defaults in r,y, g, c, b, m: +/-30°
  430. my $cc = '0, -20, -20, -25, 0, -10';
  431. $attr{$name}{"colorCast"} = $cc;
  432. WifiLight_RGB_ColorConverter($hash, split(',', $cc));
  433. # white point defaults in r,g,b
  434. $attr{$name}{"whitePoint"} = '1, 0.75, 0.25';
  435. return undef;
  436. }
  437. if (($hash->{LEDTYPE} eq 'RGB') && ($hash->{CONNECTION} =~ 'LW12FC'))
  438. {
  439. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.85);
  440. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
  441. # color cast defaults in r,y, g, c, b, m: +/-30°
  442. my $cc = '0, -20, -20, -25, 0, -10';
  443. $attr{$name}{"colorCast"} = $cc;
  444. WifiLight_RGB_ColorConverter($hash, split(',', $cc));
  445. # white point defaults in r,g,b
  446. $attr{$name}{"whitePoint"} = '1, 0.85, 0.55';
  447. return undef;
  448. }
  449. if (($hash->{LEDTYPE} eq 'RGBW') && ($hash->{CONNECTION} =~ 'LD316'))
  450. {
  451. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65);
  452. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
  453. # color cast defaults in r,y, g, c, b, m: +/-30°
  454. my $cc = '0, -25, -15, -25, 0, -20';
  455. $attr{$name}{"colorCast"} = $cc;
  456. WifiLight_RGB_ColorConverter($hash, split(',', $cc));
  457. # white point defaults in r,g,b
  458. $attr{$name}{"whitePoint"} = '1.0, 0.6, 0.065';
  459. return undef;
  460. }
  461. if (($hash->{LEDTYPE} eq 'RGBW') && ($hash->{CONNECTION} =~ 'LD316A'))
  462. {
  463. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65);
  464. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
  465. # color cast defaults in r,y, g, c, b, m: +/-30°
  466. my $cc = '0, -25, -15, -25, 0, -20';
  467. $attr{$name}{"colorCast"} = $cc;
  468. WifiLight_RGB_ColorConverter($hash, split(',', $cc));
  469. # white point defaults in r,g,b
  470. $attr{$name}{"whitePoint"} = '1.0, 0.6, 0.065';
  471. return undef;
  472. }
  473. if (($hash->{LEDTYPE} eq 'RGBW') && ($hash->{CONNECTION} =~ 'LD382'))
  474. {
  475. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65);
  476. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
  477. # color cast defaults in r,y, g, c, b, m: +/-30°
  478. my $cc = '0, -20, -20, -25, 0, -10';
  479. $attr{$name}{"colorCast"} = $cc;
  480. WifiLight_RGB_ColorConverter($hash, split(',', $cc));
  481. # white point defaults in r,g,b
  482. $attr{$name}{"whitePoint"} = '1, 1, 1';
  483. return undef;
  484. }
  485. if (($hash->{LEDTYPE} eq 'RGB') && ($hash->{CONNECTION} =~ 'LD382'))
  486. {
  487. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65);
  488. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
  489. # color cast defaults in r,y, g, c, b, m: +/-30°
  490. my $cc = '0, -20, -20, -25, 0, -10';
  491. $attr{$name}{"colorCast"} = $cc;
  492. WifiLight_RGB_ColorConverter($hash, split(',', $cc));
  493. # white point defaults in r,g,b
  494. $attr{$name}{"whitePoint"} = '1, 0.75, 0.25';
  495. return undef;
  496. }
  497. if (($hash->{LEDTYPE} eq 'RGBW') && ($hash->{CONNECTION} =~ 'LD382A'))
  498. {
  499. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65);
  500. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
  501. # color cast defaults in r,y, g, c, b, m: +/-30°
  502. my $cc = '0, -20, -20, -25, 0, -10';
  503. $attr{$name}{"colorCast"} = $cc;
  504. WifiLight_RGB_ColorConverter($hash, split(',', $cc));
  505. # white point defaults in r,g,b
  506. $attr{$name}{"whitePoint"} = '1, 1, 1';
  507. return undef;
  508. }
  509. if (($hash->{LEDTYPE} eq 'RGB') && ($hash->{CONNECTION} =~ 'LD382A'))
  510. {
  511. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65);
  512. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
  513. # color cast defaults in r,y, g, c, b, m: +/-30°
  514. my $cc = '0, -20, -20, -25, 0, -10';
  515. $attr{$name}{"colorCast"} = $cc;
  516. WifiLight_RGB_ColorConverter($hash, split(',', $cc));
  517. # white point defaults in r,g,b
  518. $attr{$name}{"whitePoint"} = '1, 0.75, 0.25';
  519. return undef;
  520. }
  521. if ((($hash->{LEDTYPE} eq 'RGB') || ($hash->{LEDTYPE} eq 'RGBW1')) && ($hash->{CONNECTION} =~ 'bridge-V[2|3]'))
  522. {
  523. return "no free slot at $hash->{CONNECTION} ($hash->{IP}) for $hash->{LEDTYPE}" if (defined($otherLights->{0}));
  524. $hash->{SLOT} = 0;
  525. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 1);
  526. $hash->{helper}->{COLORMAP} = WifiLight_Milight_ColorConverter($hash);
  527. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB sync pair unpair";
  528. #if we are allready paired: sync to get a defined state
  529. return WifiLight_RGB_Sync($hash) if ($hash->{LEDTYPE} eq 'RGB');
  530. return WifiLight_RGBW1_Sync($hash) if ($hash->{LEDTYPE} eq 'RGBW1');
  531. }
  532. elsif (($hash->{LEDTYPE} eq 'RGBW2') && ($hash->{CONNECTION} =~ 'bridge-V3'))
  533. {
  534. # find a free slot
  535. my $i = 5;
  536. while (defined($otherLights->{$i}))
  537. {
  538. $i++;
  539. }
  540. if ( grep { $i == $_ } 5..8 )
  541. {
  542. $hash->{SLOT} = $i;
  543. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.73);
  544. $hash->{helper}->{COLORMAP} = WifiLight_Milight_ColorConverter($hash);
  545. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB sync pair unpair";
  546. return WifiLight_RGBW2_Sync($hash);
  547. }
  548. else
  549. {
  550. return "no free slot at $hash->{CONNECTION} ($hash->{IP}) for $hash->{LEDTYPE}";
  551. }
  552. }
  553. elsif (($hash->{LEDTYPE} eq 'White') && ($hash->{CONNECTION} =~ 'bridge-V[2|3]'))
  554. {
  555. # find a free slot
  556. my $i = 1;
  557. while (defined($otherLights->{$i}))
  558. {
  559. $i++;
  560. }
  561. if ( grep { $i == $_ } 1..4 )
  562. {
  563. $hash->{SLOT} = $i;
  564. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.8);
  565. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown sync pair unpair";
  566. return WifiLight_White_Sync($hash);
  567. }
  568. else
  569. {
  570. return "no free slot at $hash->{CONNECTION} ($hash->{IP}) for $hash->{LEDTYPE}";
  571. }
  572. }
  573. if (($hash->{LEDTYPE} eq 'White') && ($hash->{CONNECTION} =~ 'SENGLED'))
  574. {
  575. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 1);
  576. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown";
  577. return undef;
  578. }
  579. if (($hash->{LEDTYPE} eq 'DualWhite') && ($hash->{CONNECTION} eq 'SUNRICHER'))
  580. {
  581. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65); # TODO CHECK VALUES
  582. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown";
  583. $hash->{helper}->{wLevel} = 0;
  584. # color cast defaults in r,y, g, c, b, m: +/-30°
  585. # my $cc = '0, -20, -20, -25, 0, -10'; # TODO CHECK VALUES
  586. # $attr{$name}{"colorCast"} = $cc;
  587. # WifiLight_RGB_ColorConverter($hash, split(',', $cc));
  588. # white point defaults in r,g,b
  589. # $attr{$name}{"whitePoint"} = '1, 1, 1';
  590. return undef;
  591. }
  592. if (($hash->{LEDTYPE} eq 'RGB') && ($hash->{CONNECTION} eq 'SUNRICHER'))
  593. {
  594. $hash->{helper}->{COMMANDSET} = 'on off dim dimup dimdown HSV HSVK CT RGB';
  595. # init helper
  596. $hash->{helper}->{rLevel} = 0;
  597. $hash->{helper}->{gLevel} = 0;
  598. $hash->{helper}->{bLevel} = 0;
  599. # init converter
  600. $hash->{helper}->{cmd_pwr} = 'RGBSunricher_setPWR';
  601. $hash->{helper}->{cmd_hsv} = 'RGBSunricher_setHSV';
  602. # defaults
  603. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65); # TODO CHECK VALUES
  604. # color cast defaults
  605. my $cc = '0, -20, -20, -25, 0, -10'; # TODO CHECK VALUES
  606. $attr{$name}{"colorCast"} = '0, -20, -20, -25, 0, -10';
  607. WifiLight_RGB_ColorConverter($hash, split(',', $cc));
  608. # white point defaults in r,g,b
  609. $attr{$name}{"whitePoint"} = '1, 1, 1';
  610. # TODO init readings
  611. return undef;
  612. }
  613. if (($hash->{LEDTYPE} eq 'RGB') && ($hash->{CONNECTION} eq 'SUNRICHERA'))
  614. {
  615. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65); # TODO CHECK VALUES
  616. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
  617. $hash->{helper}->{rLevel} = 0;
  618. $hash->{helper}->{gLevel} = 0;
  619. $hash->{helper}->{bLevel} = 0;
  620. # color cast defaults in r,y, g, c, b, m: +/-30°
  621. my $cc = '0, -20, -20, -25, 0, -10'; # TODO CHECK VALUES
  622. $attr{$name}{"colorCast"} = $cc;
  623. WifiLight_RGB_ColorConverter($hash, split(',', $cc));
  624. # white point defaults in r,g,b
  625. $attr{$name}{"whitePoint"} = '1, 1, 1';
  626. return undef;
  627. }
  628. if (($hash->{LEDTYPE} eq 'RGBW') && ($hash->{CONNECTION} eq 'SUNRICHER'))
  629. {
  630. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65); # TODO CHECK VALUES
  631. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
  632. $hash->{helper}->{rLevel} = 0;
  633. $hash->{helper}->{gLevel} = 0;
  634. $hash->{helper}->{bLevel} = 0;
  635. $hash->{helper}->{wLevel} = 0;
  636. # color cast defaults in r,y, g, c, b, m: +/-30°
  637. my $cc = '0, -20, -20, -25, 0, -10'; # TODO CHECK VALUES
  638. $attr{$name}{"colorCast"} = $cc;
  639. WifiLight_RGB_ColorConverter($hash, split(',', $cc));
  640. # white point defaults in r,g,b
  641. $attr{$name}{"whitePoint"} = '1, 1, 1';
  642. return undef;
  643. }
  644. if (($hash->{LEDTYPE} eq 'RGBW') && ($hash->{CONNECTION} eq 'SUNRICHERA'))
  645. {
  646. $hash->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($hash, 0.65); # TODO CHECK VALUES
  647. $hash->{helper}->{COMMANDSET} = "on off dim dimup dimdown HSV RGB";
  648. $hash->{helper}->{rLevel} = 0;
  649. $hash->{helper}->{gLevel} = 0;
  650. $hash->{helper}->{bLevel} = 0;
  651. $hash->{helper}->{wLevel} = 0;
  652. # color cast defaults in r,y, g, c, b, m: +/-30°
  653. my $cc = '0, -20, -20, -25, 0, -10'; # TODO CHECK VALUES
  654. $attr{$name}{"colorCast"} = $cc;
  655. WifiLight_RGB_ColorConverter($hash, split(',', $cc));
  656. # white point defaults in r,g,b
  657. $attr{$name}{"whitePoint"} = '1, 1, 1';
  658. return undef;
  659. }
  660. return "$hash->{LEDTYPE} is not supported at $hash->{CONNECTION} ($hash->{IP})";
  661. }
  662. sub
  663. WifiLight_Undef(@)
  664. {
  665. return undef;
  666. }
  667. sub
  668. WifiLight_Set(@)
  669. {
  670. my ($ledDevice, $name, $cmd, @args) = @_;
  671. my $descriptor = '';
  672. # remove descriptor from @args
  673. for (my $i = $#args; $i >= 0; --$i )
  674. {
  675. if ($args[$i] =~ /\/d\:(.*)/)
  676. {
  677. $descriptor = $1;
  678. splice (@args, $i, 1);
  679. }
  680. }
  681. my $cnt = @args;
  682. my $ramp = 0;
  683. my $flags = "";
  684. my $event = undef;
  685. my $cmdSet = $ledDevice->{helper}->{COMMANDSET};
  686. return "unknown command ($cmd): choose one of ".join(", ", $cmdSet) if ($cmd eq "?");
  687. return "unknown command ($cmd): choose one of ".$ledDevice->{helper}->{COMMANDSET} if ($cmd ne 'RGB') and not ( grep { $cmd eq $_ } split(" ", $ledDevice->{helper}->{COMMANDSET} ));
  688. if ($cmd eq 'pair')
  689. {
  690. WifiLight_HighLevelCmdQueue_Clear($ledDevice);
  691. if (defined($args[0]))
  692. {
  693. return "usage: set $name pair [seconds]" if ($args[0] !~ /^\d+$/);
  694. $ramp = $args[0];
  695. }
  696. return WifiLight_RGB_Pair($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  697. return WifiLight_RGBW1_Pair($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  698. return WifiLight_RGBW2_Pair($ledDevice, $ramp) if ($ledDevice->{LEDTYPE} eq 'RGBW2');
  699. return WifiLight_White_Pair($ledDevice, $ramp) if ($ledDevice->{LEDTYPE} eq 'White');
  700. }
  701. if ($cmd eq 'unpair')
  702. {
  703. WifiLight_HighLevelCmdQueue_Clear($ledDevice);
  704. if (defined($args[0]))
  705. {
  706. return "usage: set $name unpair [seconds]" if ($args[0] !~ /^\d+$/);
  707. $ramp = $args[0];
  708. }
  709. return WifiLight_RGB_UnPair($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  710. return WifiLight_RGBW1_UnPair($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  711. return WifiLight_RGBW2_UnPair($ledDevice, $ramp) if ($ledDevice->{LEDTYPE} eq 'RGBW2');
  712. return WifiLight_White_UnPair($ledDevice, $ramp) if ($ledDevice->{LEDTYPE} eq 'White');
  713. }
  714. if ($cmd eq 'sync')
  715. {
  716. WifiLight_HighLevelCmdQueue_Clear($ledDevice);
  717. return WifiLight_RGB_Sync($ledDevice) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  718. return WifiLight_RGBW1_Sync($ledDevice) if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  719. return WifiLight_RGBW2_Sync($ledDevice) if ($ledDevice->{LEDTYPE} eq 'RGBW2');
  720. return WifiLight_White_Sync($ledDevice) if ($ledDevice->{LEDTYPE} eq 'White');
  721. }
  722. if (($cmd eq 'HSV') || ($cmd eq 'RGB') || ($cmd eq 'dim'))
  723. {
  724. $args[1] = AttrVal($ledDevice->{NAME}, "defaultRamp", 0) if !defined($args[1]);
  725. }
  726. else
  727. {
  728. $args[0] = AttrVal($ledDevice->{NAME}, "defaultRamp", 0) if !defined($args[0]);
  729. }
  730. if ($cmd eq 'on')
  731. {
  732. WifiLight_HighLevelCmdQueue_Clear($ledDevice);
  733. if (defined($args[0]))
  734. {
  735. return "usage: set $name on [seconds]" if ($args[0] !~ /^\d?.?\d+$/);
  736. $ramp = $args[0];
  737. }
  738. return WifiLight_RGBWLD316_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316'));
  739. return WifiLight_RGBWLD316A_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316A'));
  740. return WifiLight_RGBWLD382_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382'));
  741. return WifiLight_RGBLD382_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382'));
  742. return WifiLight_RGBWLD382A_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382A'));
  743. return WifiLight_RGBLD382A_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382A'));
  744. return WifiLight_RGBLW12_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12'));
  745. return WifiLight_RGBLW12HX_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12HX'));
  746. return WifiLight_RGBLW12FC_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12FC'));
  747. return WifiLight_WhiteSENGLED_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} eq 'SENGLED'));
  748. return WifiLight_RGB_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  749. return WifiLight_RGBW1_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  750. return WifiLight_RGBW2_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW2') && ($ledDevice->{CONNECTION} eq 'bridge-V3'));
  751. return WifiLight_White_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  752. return WifiLight_DualWhiteSunricher_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'DualWhite') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
  753. return WifiLight_RGBSunricher_On($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} =~ /^RGB.?$/) && ($ledDevice->{CONNECTION} =~ /^SUNRICHER.?$/));
  754. }
  755. if ($cmd eq 'off')
  756. {
  757. WifiLight_HighLevelCmdQueue_Clear($ledDevice);
  758. if (defined($args[0]))
  759. {
  760. return "usage: set $name off [seconds]" if ($args[0] !~ /^\d?.?\d+$/);
  761. $ramp = $args[0];
  762. }
  763. return WifiLight_RGBWLD316_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316'));
  764. return WifiLight_RGBWLD316A_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316A'));
  765. return WifiLight_RGBWLD382_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382'));
  766. return WifiLight_RGBLD382_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382'));
  767. return WifiLight_RGBWLD382A_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382A'));
  768. return WifiLight_RGBLD382A_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382A'));
  769. return WifiLight_RGBLW12_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12'));
  770. return WifiLight_RGBLW12HX_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12HX'));
  771. return WifiLight_RGBLW12FC_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12FC'));
  772. return WifiLight_WhiteSENGLED_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} eq 'SENGLED'));
  773. return WifiLight_RGB_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  774. return WifiLight_RGBW1_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  775. return WifiLight_RGBW2_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'RGBW2') && ($ledDevice->{CONNECTION} eq 'bridge-V3'));
  776. return WifiLight_White_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  777. return WifiLight_DualWhiteSunricher_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} eq 'DualWhite') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
  778. return WifiLight_RGBSunricher_Off($ledDevice, $ramp) if (($ledDevice->{LEDTYPE} =~ /^RGB.?$/) && ($ledDevice->{CONNECTION} =~ /^SUNRICHER.?$/));
  779. }
  780. if ($cmd eq 'dimup')
  781. {
  782. return "usage: set $name dimup" if (defined($args[1]));
  783. WifiLight_HighLevelCmdQueue_Clear($ledDevice);
  784. my $v = ReadingsVal($ledDevice->{NAME}, "brightness", 0) + AttrVal($ledDevice->{NAME}, "dimStep", 7);
  785. $v = 100 if $v > 100;
  786. return WifiLight_RGBWLD316_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316'));
  787. return WifiLight_RGBWLD316A_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316A'));
  788. return WifiLight_RGBWLD382_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382'));
  789. return WifiLight_RGBLD382_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382'));
  790. return WifiLight_RGBWLD382A_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382A'));
  791. return WifiLight_RGBLD382A_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382A'));
  792. return WifiLight_RGBLW12_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12'));
  793. return WifiLight_RGBLW12HX_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12HX'));
  794. return WifiLight_RGBLW12FC_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12FC'));
  795. return WifiLight_WhiteSENGLED_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} eq 'SENGLED'));
  796. return WifiLight_RGB_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  797. return WifiLight_RGBW1_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  798. return WifiLight_RGBW2_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW2') && ($ledDevice->{CONNECTION} eq 'bridge-V3'));
  799. return WifiLight_White_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  800. return WifiLight_DualWhiteSunricher_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'DualWhite') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
  801. return WifiLight_RGBSunricher_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} =~ /^RGB.?$/) && ($ledDevice->{CONNECTION} =~ /^SUNRICHER.?$/));
  802. }
  803. if ($cmd eq 'dimdown')
  804. {
  805. return "usage: set $name dimdown" if (defined($args[1]));
  806. WifiLight_HighLevelCmdQueue_Clear($ledDevice);
  807. my $v = ReadingsVal($ledDevice->{NAME}, "brightness", 0) - AttrVal($ledDevice->{NAME}, "dimStep", 7);
  808. $v = 0 if $v < 0;
  809. return WifiLight_RGBWLD316_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316'));
  810. return WifiLight_RGBWLD316A_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316A'));
  811. return WifiLight_RGBWLD382_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382'));
  812. return WifiLight_RGBLD382_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382'));
  813. return WifiLight_RGBWLD382A_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382A'));
  814. return WifiLight_RGBLD382A_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382A'));
  815. return WifiLight_RGBLW12_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12'));
  816. return WifiLight_RGBLW12HX_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12HX'));
  817. return WifiLight_RGBLW12FC_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12FC'));
  818. return WifiLight_WhiteSENGLED_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} eq 'SENGLED'));
  819. return WifiLight_RGB_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  820. return WifiLight_RGBW1_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  821. return WifiLight_RGBW2_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'RGBW2') && ($ledDevice->{CONNECTION} eq 'bridge-V3'));
  822. return WifiLight_White_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  823. return WifiLight_DualWhiteSunricher_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} eq 'DualWhite') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
  824. return WifiLight_RGBSunricher_Dim($ledDevice, $v, 0, '') if (($ledDevice->{LEDTYPE} =~ /^RGB.?$/) && ($ledDevice->{CONNECTION} =~ /^SUNRICHER.?$/));
  825. }
  826. if ($cmd eq 'dim')
  827. {
  828. return "usage: set $name dim level [seconds]" if ($args[0] !~ /^\d+$/);
  829. return "usage: set $name dim level [seconds]" if (($args[0] < 0) || ($args[0] > 100));
  830. if (defined($args[1]))
  831. {
  832. return "usage: set $name dim level [seconds] [q]" if ($args[1] !~ /^\d?.?\d+$/);
  833. $ramp = $args[1];
  834. }
  835. if (defined($args[2]))
  836. {
  837. return "usage: set $name dim level seconds [q]" if ($args[2] !~ m/.*[qQ].*/);
  838. $flags = $args[2];
  839. }
  840. WifiLight_HighLevelCmdQueue_Clear($ledDevice) if ($flags !~ m/.*[qQ].*/);
  841. return WifiLight_RGBWLD316_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316'));
  842. return WifiLight_RGBWLD316A_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316A'));
  843. return WifiLight_RGBWLD382_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382'));
  844. return WifiLight_RGBLD382_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382'));
  845. return WifiLight_RGBWLD382A_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382A'));
  846. return WifiLight_RGBLD382A_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382A'));
  847. return WifiLight_RGBLW12_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12'));
  848. return WifiLight_RGBLW12HX_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12HX'));
  849. return WifiLight_RGBLW12FC_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LW12FC'));
  850. return WifiLight_WhiteSENGLED_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} eq 'SENGLED'));
  851. return WifiLight_RGB_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  852. return WifiLight_RGBW1_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  853. return WifiLight_RGBW2_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'RGBW2') && ($ledDevice->{CONNECTION} eq 'bridge-V3'));
  854. return WifiLight_White_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  855. return WifiLight_DualWhiteSunricher_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} eq 'DualWhite') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
  856. return WifiLight_RGBSunricher_Dim($ledDevice, $args[0], $ramp, $flags) if (($ledDevice->{LEDTYPE} =~ /^RGB.?$/) && ($ledDevice->{CONNECTION} =~ /^SUNRICHER.?$/));
  857. }
  858. if (($cmd eq 'HSV') || ($cmd eq 'RGB'))
  859. {
  860. my ($hue, $sat, $val);
  861. if ($cmd eq 'HSV')
  862. {
  863. return "HSV is required as h,s,v" if (defined($args[0]) && $args[0] !~ /^\d{1,3},\d{1,3},\d{1,3}$/);
  864. ($hue, $sat, $val) = split(',', $args[0]);
  865. return "wrong hue ($hue): valid range 0..360" if !(($hue >= 0) && ($hue <= 360));
  866. return "wrong saturation ($sat): valid range 0..100" if !(($sat >= 0) && ($sat <= 100));
  867. return "wrong brightness ($val): valid range 0..100" if !(($val >= 0) && ($val <= 100));
  868. }
  869. elsif ($cmd eq 'RGB')
  870. {
  871. return "RGB is required hex RRGGBB" if (defined($args[0]) && $args[0] !~ /^[0-9A-Fa-f]{6}$/);
  872. ($hue, $sat, $val) = WifiLight_RGB2HSV($ledDevice, $args[0]);
  873. }
  874. if (defined($args[1]))
  875. {
  876. return "usage: set $name HSV H,S,V seconds flags programm" if ($args[1] !~ /^\d?.?\d+$/);
  877. $ramp = $args[1];
  878. }
  879. if (defined($args[2]))
  880. {
  881. return "usage: set $name HSV H,S,V seconds [slq] programm" if ($args[2] !~ m/.*[sSlLqQ].*/);
  882. $flags = $args[2];
  883. }
  884. if (defined($args[3]))
  885. {
  886. return "usage: set $name HSV H,S,V seconds flags programm=[A-Za-z_0-9]" if ($args[3] !~ m/[A-Za-z_0-9]*/);
  887. $event = $args[3];
  888. }
  889. WifiLight_HighLevelCmdQueue_Clear($ledDevice) if ($flags !~ m/.*[qQ].*/);
  890. WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 100, $event) if ($ledDevice->{CONNECTION} eq 'LD316');
  891. WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 100, $event) if ($ledDevice->{CONNECTION} eq 'LD316A');
  892. WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 100, $event) if ($ledDevice->{CONNECTION} eq 'LD382');
  893. WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 100, $event) if ($ledDevice->{CONNECTION} eq 'LD382A');
  894. WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 100, $event) if ($ledDevice->{CONNECTION} eq 'LW12');
  895. WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 100, $event) if ($ledDevice->{CONNECTION} eq 'LW12HX');
  896. WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 100, $event) if ($ledDevice->{CONNECTION} eq 'LW12FC');
  897. WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 500, $event) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  898. WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 1000, $event) if (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  899. WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 200, $event) if (($ledDevice->{LEDTYPE} eq 'RGBW2') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  900. WifiLight_HSV_Transition($ledDevice, $hue, $sat, $val, $ramp, $flags, 100, $event) if (($ledDevice->{LEDTYPE} =~ /^RGB.?$/) && ($ledDevice->{CONNECTION} =~ /^SUNRICHER.?$/));
  901. return WifiLight_SetHSV_Target($ledDevice, $hue, $sat, $val);
  902. }
  903. }
  904. sub
  905. WifiLight_Get(@)
  906. {
  907. my ($ledDevice, $name, $cmd, @args) = @_;
  908. my $cnt = @args;
  909. return undef;
  910. }
  911. sub
  912. WifiLight_Attr(@)
  913. {
  914. my ($cmd, $device, $attribName, $attribVal) = @_;
  915. my $ledDevice = $defs{$device};
  916. if ($cmd eq 'set' && $attribName eq 'gamma')
  917. {
  918. return "gamma is required as numerical value (eg. 0.5 or 2.2)" if ($attribVal !~ /^\d*\.\d*$/);
  919. $ledDevice->{helper}->{GAMMAMAP} = WifiLight_CreateGammaMapping($ledDevice, $attribVal);
  920. }
  921. if ($cmd eq 'set' && $attribName eq 'dimStep')
  922. {
  923. return "dimStep is required as numerical value [1..100]" if ($attribVal !~ /^\d*$/) || (($attribVal < 1) || ($attribVal > 100));
  924. }
  925. if ($cmd eq 'set' && $attribName eq 'defaultColor')
  926. {
  927. return "defaultColor is required as HSV" if ($attribVal !~ /^\d{1,3},\d{1,3},\d{1,3}$/);
  928. my ($hue, $sat, $val) = split(',', $attribVal);
  929. return "defaultColor: wrong hue ($hue): valid range 0..360" if !(($hue >= 0) && ($hue <= 360));
  930. return "defaultColor: wrong saturation ($sat): valid range 0..100" if !(($sat >= 0) && ($sat <= 100));
  931. return "defaultColor: wrong brightness ($val): valid range 0..100" if !(($val >= 0) && ($val <= 100));
  932. }
  933. my @a = ();
  934. if ($cmd eq 'set' && $attribName eq 'colorCast')
  935. {
  936. @a = split(',', $attribVal);
  937. my $msg = "colorCast: correction require red, yellow, green ,cyan, blue, magenta (each in a range of -29 .. 29)";
  938. return $msg unless (@a == 6);
  939. foreach my $tc (@a)
  940. {
  941. return $msg unless ($tc =~ m/^\s*[\-]{0,1}[0-9]+[\.]{0,1}[0-9]*\s*$/g);
  942. return $msg if (abs($tc) >= 30);
  943. }
  944. WifiLight_RGB_ColorConverter($ledDevice, @a) if ($ledDevice->{CONNECTION} eq 'LD316');
  945. WifiLight_RGB_ColorConverter($ledDevice, @a) if ($ledDevice->{CONNECTION} eq 'LD316A');
  946. WifiLight_RGB_ColorConverter($ledDevice, @a) if ($ledDevice->{CONNECTION} eq 'LD382');
  947. WifiLight_RGB_ColorConverter($ledDevice, @a) if ($ledDevice->{CONNECTION} eq 'LD382A');
  948. WifiLight_RGB_ColorConverter($ledDevice, @a) if ($ledDevice->{CONNECTION} eq 'LW12');
  949. WifiLight_RGB_ColorConverter($ledDevice, @a) if ($ledDevice->{CONNECTION} eq 'LW12HX');
  950. WifiLight_RGB_ColorConverter($ledDevice, @a) if ($ledDevice->{CONNECTION} eq 'LW12FC');
  951. WifiLight_Milight_ColorConverter($ledDevice, @a) if ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]');
  952. WifiLight_RGB_ColorConverter($ledDevice, @a) if (($ledDevice->{LEDTYPE} =~ /^RGB.?$/) && ($ledDevice->{CONNECTION} =~ /^SUNRICHER.?$/));
  953. if ($init_done && !(@{$ledDevice->{helper}->{hlCmdQueue}}))
  954. {
  955. my $hue = $ledDevice->{READINGS}->{hue}->{VAL};
  956. my $sat = $ledDevice->{READINGS}->{saturation}->{VAL};
  957. my $val = $ledDevice->{READINGS}->{brightness}->{VAL};
  958. WifiLight_setHSV($ledDevice, $hue, $sat, $val, 1);
  959. }
  960. }
  961. if ($cmd eq 'set' && $attribName eq 'whitePoint')
  962. {
  963. @a = split(',', $attribVal);
  964. my $msg = "whitePoint: correction require red, green, blue (each in a range of 0.0 ..1.0)";
  965. return $msg unless (@a == 3);
  966. foreach my $tc (@a)
  967. {
  968. return $msg unless ($tc =~ m/^\s*[0-9]+?[\.]{0,1}[0-9]*\s*$/g);
  969. return $msg if (($tc < 0) || ($tc > 1));
  970. }
  971. if ($init_done && !(@{$ledDevice->{helper}->{hlCmdQueue}}))
  972. {
  973. $attr{$device}{"whitePoint"} = $attribVal;
  974. my $hue = $ledDevice->{READINGS}->{hue}->{VAL};
  975. my $sat = $ledDevice->{READINGS}->{saturation}->{VAL};
  976. my $val = $ledDevice->{READINGS}->{brightness}->{VAL};
  977. WifiLight_setHSV($ledDevice, $hue, $sat, $val, 1);
  978. }
  979. }
  980. Log3 ($ledDevice, 4, "$ledDevice->{NAME} attrib $attribName $cmd $attribVal") if $attribVal;
  981. return undef;
  982. }
  983. # restore previous settings (as set statefile)
  984. sub
  985. WifiLight_Notify(@)
  986. {
  987. my ($ledDevice, $eventSrc) = @_;
  988. my $events = deviceEvents($eventSrc, 1);
  989. my ($hue, $sat, $val);
  990. # wait for global: INITIALIZED after start up
  991. if ($eventSrc->{NAME} eq 'global' && @{$events}[0] eq 'INITIALIZED')
  992. {
  993. #######################################################
  994. # TODO remove in a few weeks. its here for convenience
  995. delete($ledDevice->{READINGS}->{HUE});
  996. delete($ledDevice->{READINGS}->{SATURATION});
  997. delete($ledDevice->{READINGS}->{BRIGHTNESS});
  998. #######################################################
  999. if ($ledDevice->{CONNECTION} eq 'LW12')
  1000. {
  1001. $hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
  1002. $sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
  1003. $val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:0;
  1004. return WifiLight_RGBLW12_setHSV($ledDevice, $hue, $sat, $val);
  1005. }
  1006. elsif ($ledDevice->{CONNECTION} eq 'LW12HX')
  1007. {
  1008. $hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
  1009. $sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
  1010. $val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:0;
  1011. return WifiLight_RGBLW12HX_setHSV($ledDevice, $hue, $sat, $val);
  1012. }
  1013. elsif ($ledDevice->{CONNECTION} eq 'LW12FC')
  1014. {
  1015. $hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
  1016. $sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
  1017. $val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:0;
  1018. return WifiLight_RGBLW12FC_setHSV($ledDevice, $hue, $sat, $val);
  1019. }
  1020. elsif ($ledDevice->{CONNECTION} eq 'LD316')
  1021. {
  1022. $hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
  1023. $sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
  1024. $val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:0;
  1025. return WifiLight_RGBWLD316_setHSV($ledDevice, $hue, $sat, $val);
  1026. }
  1027. elsif ($ledDevice->{CONNECTION} eq 'LD316A')
  1028. {
  1029. $hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
  1030. $sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
  1031. $val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:0;
  1032. return WifiLight_RGBWLD316A_setHSV($ledDevice, $hue, $sat, $val);
  1033. }
  1034. elsif ($ledDevice->{CONNECTION} eq 'LD382')
  1035. {
  1036. $hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
  1037. $sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
  1038. $val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:0;
  1039. return WifiLight_RGBWLD382_setHSV($ledDevice, $hue, $sat, $val);
  1040. }
  1041. elsif ($ledDevice->{CONNECTION} eq 'LD382A')
  1042. {
  1043. $hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
  1044. $sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
  1045. $val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:0;
  1046. return WifiLight_RGBWLD382A_setHSV($ledDevice, $hue, $sat, $val);
  1047. }
  1048. elsif (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'))
  1049. {
  1050. $hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:60;
  1051. $sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:100;
  1052. $val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:100;
  1053. return WifiLight_RGB_setHSV($ledDevice, $hue, $sat, $val);
  1054. }
  1055. elsif (($ledDevice->{LEDTYPE} eq 'RGBW1') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'))
  1056. {
  1057. $hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
  1058. $sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:50;
  1059. $val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:100;
  1060. return WifiLight_RGBW1_setHSV($ledDevice, $hue, $sat, $val);
  1061. }
  1062. elsif (($ledDevice->{LEDTYPE} eq 'RGBW2') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'))
  1063. {
  1064. $hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
  1065. $sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
  1066. $val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:0;
  1067. return WifiLight_RGBW2_setHSV($ledDevice, $hue, $sat, $val);
  1068. }
  1069. elsif (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'))
  1070. {
  1071. $hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
  1072. $sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
  1073. $val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:100;
  1074. return WifiLight_White_setHSV($ledDevice, $hue, $sat, $val);
  1075. }
  1076. elsif (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} eq 'SENGLED'))
  1077. {
  1078. $hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
  1079. $sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
  1080. $val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:100;
  1081. return WifiLight_WhiteSENGLED_setHSV($ledDevice, $hue, $sat, $val);
  1082. }
  1083. elsif (($ledDevice->{LEDTYPE} =~ /^RGB.?$/) && ($ledDevice->{CONNECTION} =~ /^SUNRICHER.?$/))
  1084. {
  1085. $hue = defined($ledDevice->{READINGS}->{hue}->{VAL})?$ledDevice->{READINGS}->{hue}->{VAL}:0;
  1086. $sat = defined($ledDevice->{READINGS}->{saturation}->{VAL})?$ledDevice->{READINGS}->{saturation}->{VAL}:0;
  1087. $val = defined($ledDevice->{READINGS}->{brightness}->{VAL})?$ledDevice->{READINGS}->{brightness}->{VAL}:100;
  1088. return WifiLight_RGBSunricher_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
  1089. return WifiLight_RGBSunricherA_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'SUNRICHERA'));
  1090. return WifiLight_RGBWSunricher_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
  1091. return WifiLight_RGBWSunricherA_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'SUNRICHERA'));
  1092. }
  1093. #
  1094. else
  1095. {
  1096. }
  1097. return
  1098. }
  1099. }
  1100. ###############################################################################
  1101. #
  1102. # generic device types
  1103. # RGB device
  1104. #
  1105. #
  1106. ###############################################################################
  1107. sub
  1108. WifiLight_RGBDevice_On(@)
  1109. {
  1110. my ($ledDevice, $ramp) = @_;
  1111. my $delay = 50;
  1112. my $on = pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x02, 0x12, 0xAB, 0x00, 0xAA, 0xAA );
  1113. my $receiver;
  1114. $on = WifiLight_Sunricher_Checksum($ledDevice, $on);
  1115. WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
  1116. # TODO device specific on
  1117. my ($h, $s, $v, $k) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100, 3200"));
  1118. Log3 ($ledDevice, 3, "$ledDevice->{NAME} $ledDevice->{LEDTYPE} $ledDevice->{CONNECTION} set on ($h, $s, $v) $ramp");
  1119. return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
  1120. }
  1121. sub
  1122. WifiLight_RGBDevice_Off(@)
  1123. {
  1124. my ($ledDevice, $ramp) = @_;
  1125. Log3 ($ledDevice, 3, "$ledDevice->{NAME} $ledDevice->{LEDTYPE} $ledDevice->{CONNECTION} set off $ramp");
  1126. return WifiLight_RGBDevice_Dim($ledDevice, 0, $ramp, '');
  1127. }
  1128. sub
  1129. WifiLight_RGBDevice_Dim(@)
  1130. {
  1131. my ($ledDevice, $level, $ramp, $flags) = @_;
  1132. my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  1133. my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  1134. Log3 ($ledDevice, 3, "$ledDevice->{NAME} $ledDevice->{LEDTYPE} $ledDevice->{CONNECTION} dim $level $ramp $flags");
  1135. return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
  1136. }
  1137. ###############################################################################
  1138. #
  1139. # device specific controller functions DualWhite SUNRICHER
  1140. #
  1141. #
  1142. #
  1143. ###############################################################################
  1144. sub
  1145. WifiLight_DualWhiteSunricher_On(@)
  1146. {
  1147. my ($ledDevice, $ramp) = @_;
  1148. my $delay = 50;
  1149. my $on = pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x02, 0x12, 0xAB, 0x00, 0xAA, 0xAA );
  1150. my $receiver;
  1151. $on = WifiLight_Sunricher_Checksum($ledDevice, $on);
  1152. WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
  1153. my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
  1154. Log3 ($ledDevice, 3, "$ledDevice->{NAME} DualWhite Sunricher set on ($v) $ramp");
  1155. return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
  1156. }
  1157. sub
  1158. WifiLight_DualWhiteSunricher_Off(@)
  1159. {
  1160. my ($ledDevice, $ramp) = @_;
  1161. Log3 ($ledDevice, 3, "$ledDevice->{NAME} DualWhite Sunricher set off $ramp");
  1162. return WifiLight_DualWhiteSunricher_Dim($ledDevice, 0, $ramp, '');
  1163. }
  1164. sub
  1165. WifiLight_DualWhiteSunricher_Dim(@)
  1166. {
  1167. my ($ledDevice, $level, $ramp, $flags) = @_;
  1168. my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  1169. my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  1170. Log3 ($ledDevice, 3, "$ledDevice->{NAME} DualWhite Sunricher dim $level $ramp $flags");
  1171. return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
  1172. }
  1173. sub
  1174. WifiLight_DualWhiteSunricher_setHSV(@)
  1175. {
  1176. my ($ledDevice, $hue, $sat, $val, $ct) = @_;
  1177. my $receiver; # = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  1178. my $delay = 0;
  1179. Log3 ($ledDevice, 4, "$ledDevice->{NAME} DualWhite Sunricher set h:$hue, s:$sat, v:$val");
  1180. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  1181. # apply gamma correction
  1182. my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
  1183. my $wt = int($gammaVal * 0x40 / 100);
  1184. my $msg;
  1185. # Me$msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x36, 0x10, 0x00, 0xAA, 0xAA));
  1186. $msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x33, $wt, 0x00, 0xAA, 0xAA));
  1187. # lock ll queue to prevent a bottleneck within llqueue
  1188. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  1189. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  1190. $ledDevice->{helper}->{llLock} += 1;
  1191. WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  1192. # unlock ll queue
  1193. return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  1194. }
  1195. ###############################################################################
  1196. #
  1197. # device specific controller functions RGBW SUNRICHER
  1198. # device range 0x00 0xff
  1199. #
  1200. #
  1201. ###############################################################################
  1202. sub
  1203. WifiLight_RGBSunricher_On(@)
  1204. {
  1205. my ($ledDevice, $ramp) = @_;
  1206. my $delay = 50;
  1207. my $on = pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x02, 0x12, 0xAB, 0x00, 0xAA, 0xAA );
  1208. my $receiver;
  1209. $on = WifiLight_Sunricher_Checksum($ledDevice, $on);
  1210. WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
  1211. my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
  1212. Log3 ($ledDevice, 3, "$ledDevice->{NAME} $ledDevice->{LEDTYPE} $ledDevice->{CONNECTION} set on ($h, $s, $v) $ramp");
  1213. return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
  1214. }
  1215. sub
  1216. WifiLight_RGBSunricher_Off(@)
  1217. {
  1218. my ($ledDevice, $ramp) = @_;
  1219. Log3 ($ledDevice, 3, "$ledDevice->{NAME} $ledDevice->{LEDTYPE} $ledDevice->{CONNECTION} set off $ramp");
  1220. return WifiLight_RGBWLD382_Dim($ledDevice, 0, $ramp, '');
  1221. }
  1222. sub
  1223. WifiLight_RGBSunricher_Dim(@)
  1224. {
  1225. my ($ledDevice, $level, $ramp, $flags) = @_;
  1226. my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  1227. my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  1228. Log3 ($ledDevice, 3, "$ledDevice->{NAME} $ledDevice->{LEDTYPE} $ledDevice->{CONNECTION} dim $level $ramp $flags");
  1229. return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
  1230. }
  1231. ###############################################################################
  1232. #
  1233. # SUNRICHER Color conversation functions
  1234. #
  1235. #
  1236. #
  1237. ###############################################################################
  1238. sub
  1239. WifiLight_RGBSunricher_setHSV(@)
  1240. {
  1241. my ($ledDevice, $hue, $sat, $val) = @_;
  1242. my $receiver; # = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  1243. my $delay = 0;
  1244. my $msg = '';
  1245. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW Sunricher set h:$hue, s:$sat, v:$val");
  1246. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  1247. # apply gamma correction
  1248. my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
  1249. # color cast correction
  1250. my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
  1251. # convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
  1252. my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
  1253. $rr = int( $rr * 0x80 / 0xFF );
  1254. $rg = int( $rg * 0x80 / 0xFF );
  1255. $rb = int( $rb * 0x80 / 0xFF );
  1256. $white = int( $white * 0x80 / 0xFF );
  1257. # TODO CT and white point correction
  1258. $rr += $white;
  1259. $rg += $white;
  1260. $rb += $white;
  1261. $msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x18, $rr, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{rLevel} != $rr);
  1262. $msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x19, $rg, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{gLevel} != $rg);
  1263. $msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x20, $rb, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{bLevel} != $rb);
  1264. $ledDevice->{helper}->{rLevel} = $rr;
  1265. $ledDevice->{helper}->{rLevel} = $rg;
  1266. $ledDevice->{helper}->{rLevel} = $rb;
  1267. # leave here if nothing to tell
  1268. return unless $msg;
  1269. # lock ll queue to prevent a bottleneck within llqueue
  1270. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  1271. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  1272. $ledDevice->{helper}->{llLock} += 1;
  1273. WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  1274. # unlock ll queue
  1275. return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  1276. }
  1277. sub
  1278. WifiLight_RGBSunricherA_setHSV(@)
  1279. {
  1280. my ($ledDevice, $hue, $sat, $val) = @_;
  1281. my $receiver; # = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  1282. my $delay = 0;
  1283. my $msg = '';
  1284. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW Sunricher set h:$hue, s:$sat, v:$val");
  1285. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  1286. # apply gamma correction
  1287. my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
  1288. # color cast correction
  1289. my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
  1290. # convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
  1291. my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
  1292. # TODO CT and white point correction
  1293. $rr += $white;
  1294. $rg += $white;
  1295. $rb += $white;
  1296. $msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x18, $rr, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{rLevel} != $rr);
  1297. $msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x19, $rg, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{gLevel} != $rg);
  1298. $msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x20, $rb, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{bLevel} != $rb);
  1299. $ledDevice->{helper}->{rLevel} = $rr;
  1300. $ledDevice->{helper}->{rLevel} = $rg;
  1301. $ledDevice->{helper}->{rLevel} = $rb;
  1302. # leave here if nothing to tell
  1303. return unless $msg;
  1304. # lock ll queue to prevent a bottleneck within llqueue
  1305. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  1306. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  1307. $ledDevice->{helper}->{llLock} += 1;
  1308. WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  1309. # unlock ll queue
  1310. return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  1311. }
  1312. sub
  1313. WifiLight_RGBWSunricher_setHSV(@)
  1314. {
  1315. my ($ledDevice, $hue, $sat, $val) = @_;
  1316. my $receiver; # = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  1317. my $delay = 0;
  1318. my $msg = '';
  1319. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW Sunricher set h:$hue, s:$sat, v:$val");
  1320. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  1321. # apply gamma correction
  1322. my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
  1323. # color cast correction
  1324. my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
  1325. # convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
  1326. my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
  1327. $rr = int( $rr * 0x80 / 0xFF );
  1328. $rg = int( $rg * 0x80 / 0xFF );
  1329. $rb = int( $rb * 0x80 / 0xFF );
  1330. $white = int( $white * 0x80 / 0xFF );
  1331. $msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x18, $rr, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{rLevel} != $rr);
  1332. $msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x19, $rg, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{gLevel} != $rg);
  1333. $msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x20, $rb, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{bLevel} != $rb);
  1334. $msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x21, $white, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{wLevel} != $white);
  1335. $ledDevice->{helper}->{rLevel} = $rr;
  1336. $ledDevice->{helper}->{rLevel} = $rg;
  1337. $ledDevice->{helper}->{rLevel} = $rb;
  1338. $ledDevice->{helper}->{rLevel} = $white;
  1339. # leave here if nothing to tell
  1340. return unless $msg;
  1341. # lock ll queue to prevent a bottleneck within llqueue
  1342. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  1343. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  1344. $ledDevice->{helper}->{llLock} += 1;
  1345. WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  1346. # unlock ll queue
  1347. return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  1348. }
  1349. sub
  1350. WifiLight_RGBWSunricherA_setHSV(@)
  1351. {
  1352. my ($ledDevice, $hue, $sat, $val) = @_;
  1353. my $receiver; # = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  1354. my $delay = 0;
  1355. my $msg = '';
  1356. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW Sunricher set h:$hue, s:$sat, v:$val");
  1357. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  1358. # apply gamma correction
  1359. my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
  1360. # color cast correction
  1361. my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
  1362. # convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
  1363. my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
  1364. $rr *= 0x80 / 0xFF;
  1365. $msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x18, $rr, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{rLevel} != $rr);
  1366. $msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x19, $rg, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{gLevel} != $rg);
  1367. $msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x20, $rb, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{bLevel} != $rb);
  1368. $msg .= WifiLight_Sunricher_Checksum($ledDevice, pack('C*', 0x55, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x08, 0x21, $white, 0x00, 0xAA, 0xAA)) if ($ledDevice->{helper}->{wLevel} != $white);
  1369. $ledDevice->{helper}->{rLevel} = $rr;
  1370. $ledDevice->{helper}->{rLevel} = $rg;
  1371. $ledDevice->{helper}->{rLevel} = $rb;
  1372. $ledDevice->{helper}->{rLevel} = $white;
  1373. # leave here if nothing to tell
  1374. return unless $msg;
  1375. # lock ll queue to prevent a bottleneck within llqueue
  1376. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  1377. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  1378. $ledDevice->{helper}->{llLock} += 1;
  1379. WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  1380. # unlock ll queue
  1381. return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  1382. }
  1383. ###############################################################################
  1384. #
  1385. # SUNRICHER helper functions
  1386. #
  1387. #
  1388. ###############################################################################
  1389. sub
  1390. WifiLight_Sunricher_Checksum(@)
  1391. {
  1392. my ($ledDevice, $msg) = @_;
  1393. my @byteStream = unpack('C*', $msg);
  1394. my $l = @byteStream;
  1395. my $c = 0;
  1396. for (my $i=4; $i<($l-3); $i++) {
  1397. $c += $byteStream[$i];
  1398. }
  1399. $c %= 0x100;
  1400. $byteStream[$l -3] = $c;
  1401. $msg = pack('C*', @byteStream);
  1402. return $msg;
  1403. }
  1404. ###############################################################################
  1405. #
  1406. # device specific controller functions RGBW LD316
  1407. # aka XScource
  1408. #
  1409. #
  1410. ###############################################################################
  1411. sub
  1412. WifiLight_RGBWLD316_On(@)
  1413. {
  1414. my ($ledDevice, $ramp) = @_;
  1415. my $delay = 50;
  1416. my $on = sprintf("%c%c%c", 0xCC, 0x23, 0x33);
  1417. my $msg = sprintf("%c%c%c%c%c", 0x56, 0, 0, 0, 0xAA);
  1418. my $receiver;
  1419. WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
  1420. my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
  1421. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD316 set on ($h, $s, $v) $ramp");
  1422. return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
  1423. }
  1424. sub
  1425. WifiLight_RGBWLD316_Off(@)
  1426. {
  1427. my ($ledDevice, $ramp) = @_;
  1428. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD316 set off $ramp");
  1429. return WifiLight_RGBWLD316_Dim($ledDevice, 0, $ramp, '');
  1430. }
  1431. sub
  1432. WifiLight_RGBWLD316_Dim(@)
  1433. {
  1434. my ($ledDevice, $level, $ramp, $flags) = @_;
  1435. my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  1436. my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  1437. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD316 dim $level $ramp $flags");
  1438. return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
  1439. }
  1440. sub
  1441. WifiLight_RGBWLD316_setHSV(@)
  1442. {
  1443. my ($ledDevice, $hue, $sat, $val, $k) = @_;
  1444. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  1445. my $delay = 50;
  1446. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW LD316 set h:$hue, s:$sat, v:$val");
  1447. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  1448. # apply gamma correction, may be doing it after wb more ok
  1449. my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
  1450. ##########################################
  1451. # sat is spread by 10% so there is room
  1452. # for a smoth switch to white and adapt to
  1453. # higher brightness of white led
  1454. ##########################################
  1455. $sat = ($sat * 1.1) -10;
  1456. my $wl = ($sat<0)?$sat * -1:0;
  1457. $sat = ($sat<0)?0:$sat;
  1458. # color cast correction
  1459. my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
  1460. # convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
  1461. my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
  1462. my $msg;
  1463. ##########################################
  1464. # experimental white temp adjustment
  1465. # G - 50%
  1466. # B - 04%
  1467. # sat is spread by 10% so there is room
  1468. # for a smoth switch to white and adapt to
  1469. # higher brightness of whte led
  1470. ##########################################
  1471. my ($wr, $wg, $wb) = split(',', AttrVal($ledDevice->{NAME}, 'whitePoint', '1, 1, 1'));
  1472. # rgb mode
  1473. if (($val > 0) && ($wl == 0))
  1474. {
  1475. #replace the removed part of white light and apply white balance
  1476. $rr += int(($white * $wr) + 0.5);
  1477. $rg += int(($white * $wg) + 0.5);
  1478. $rb += int(($white * $wb) + 0.5);
  1479. #new proto 0x56, r, g, b, white level, f0 (color) || 0f (white), 0xaa (terminator)
  1480. $msg = sprintf("%c%c%c%c%c%c%c", 0x56, $rr, $rg, $rb, 0x00, 0xF0, 0xAA);
  1481. }
  1482. elsif ($wl > 0)
  1483. {
  1484. #smoth brightness adaption of white led
  1485. my $wo = $gammaVal - ($gammaVal * (10-$wl) * 0.08); #0.07
  1486. $wo = int(0.5 + ($wo * 2.55));
  1487. $msg = sprintf("%c%c%c%c%c%c%c", 0x56, 0, 0, 0, $wo, 0x0F, 0xAA);
  1488. }
  1489. else
  1490. {
  1491. $msg = sprintf("%c%c%c%c%c%c%c", 0x56, 0, 0, 0, 0x00, 0xF0, 0xAA);
  1492. }
  1493. # lock ll queue to prevent a bottleneck within llqueue
  1494. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  1495. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  1496. $ledDevice->{helper}->{llLock} += 1;
  1497. WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  1498. # unlock ll queue
  1499. return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  1500. }
  1501. ###############################################################################
  1502. #
  1503. # device specific controller functions RGBW LD316A - new fw.
  1504. # thnx raspklaus
  1505. #
  1506. ###############################################################################
  1507. sub
  1508. WifiLight_RGBWLD316A_On(@)
  1509. {
  1510. my ($ledDevice, $ramp) = @_;
  1511. my $delay = 50;
  1512. my $on = sprintf("%c%c%c%c", 0x71, 0x23, 0x0F, 0xA3);
  1513. my $msg = sprintf("%c%c%c%c%c", 0x56, 0, 0, 0, 0xAA);
  1514. my $receiver;
  1515. WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
  1516. my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
  1517. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD316A set on ($h, $s, $v) $ramp");
  1518. return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
  1519. }
  1520. sub
  1521. WifiLight_RGBWLD316A_Off(@)
  1522. {
  1523. my ($ledDevice, $ramp) = @_;
  1524. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD316A set off $ramp");
  1525. return WifiLight_RGBWLD316_Dim($ledDevice, 0, $ramp, '');
  1526. }
  1527. sub
  1528. WifiLight_RGBWLD316A_Dim(@)
  1529. {
  1530. my ($ledDevice, $level, $ramp, $flags) = @_;
  1531. my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  1532. my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  1533. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD316A dim $level $ramp $flags");
  1534. return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
  1535. }
  1536. sub
  1537. WifiLight_RGBWLD316A_setHSV(@)
  1538. {
  1539. my ($ledDevice, $hue, $sat, $val) = @_;
  1540. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  1541. my $delay = 50;
  1542. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW LD316A set h:$hue, s:$sat, v:$val");
  1543. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  1544. # apply gamma correction, may be doing it after wb more ok
  1545. my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
  1546. ##########################################
  1547. # sat is spread by 10% so there is room
  1548. # for a smoth switch to white and adapt to
  1549. # higher brightness of white led
  1550. ##########################################
  1551. $sat = ($sat * 1.1) -10;
  1552. my $wl = ($sat<0)?$sat * -1:0;
  1553. $sat = ($sat<0)?0:$sat;
  1554. # color cast correction
  1555. my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
  1556. # convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
  1557. my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
  1558. my $msg;
  1559. ##########################################
  1560. # experimental white temp adjustment
  1561. # G - 50%
  1562. # B - 04%
  1563. # sat is spread by 10% so there is room
  1564. # for a smoth switch to white and adapt to
  1565. # higher brightness of whte led
  1566. ##########################################
  1567. my ($wr, $wg, $wb) = split(',', AttrVal($ledDevice->{NAME}, 'whitePoint', '1, 1, 1'));
  1568. # rgb mode
  1569. if (($val > 0) && ($wl == 0))
  1570. {
  1571. #replace the removed part of white light and apply white balance
  1572. $rr += int(($white * $wr) + 0.5);
  1573. $rg += int(($white * $wg) + 0.5);
  1574. $rb += int(($white * $wb) + 0.5);
  1575. #new proto 0x56, r, g, b, white level, f0 (color) || 0f (white), 0xaa (terminator)
  1576. $msg = sprintf("%c%c%c%c%c%c%c", 0x31, $rr, $rg, $rb, 0x00, 0xF0, 0x0F);
  1577. }
  1578. elsif ($wl > 0)
  1579. {
  1580. #smoth brightness adaption of white led
  1581. my $wo = $gammaVal - ($gammaVal * (10-$wl) * 0.08); #0.07
  1582. $wo = int(0.5 + ($wo * 2.55));
  1583. $msg = sprintf("%c%c%c%c%c%c%c", 0x31, 0, 0, 0, $wo, 0x0F, 0x0F);
  1584. }
  1585. else
  1586. {
  1587. $msg = sprintf("%c%c%c%c%c%c%c", 0x31, 0, 0, 0, 0x00, 0xF0, 0x0F);
  1588. }
  1589. #add checksum
  1590. $msg = WifiLight_RGBWLD382_Checksum($ledDevice, $msg);
  1591. # lock ll queue to prevent a bottleneck within llqueue
  1592. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  1593. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  1594. $ledDevice->{helper}->{llLock} += 1;
  1595. WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  1596. # unlock ll queue
  1597. return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  1598. }
  1599. ###############################################################################
  1600. #
  1601. # device specific controller functions LD382 aka Magic UFO
  1602. # with RGBW stripe (RGB and white)
  1603. #
  1604. #
  1605. ###############################################################################
  1606. sub
  1607. WifiLight_RGBWLD382_On(@)
  1608. {
  1609. my ($ledDevice, $ramp) = @_;
  1610. my $delay = 50;
  1611. my $on = sprintf("%c%c%c", 0x71, 0x23, 0x94);
  1612. my $msg = sprintf("%c%c%c%c%c", 0x56, 0, 0, 0, 0xAA);
  1613. my $receiver;
  1614. WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
  1615. my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
  1616. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD382 set on ($h, $s, $v) $ramp");
  1617. return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
  1618. }
  1619. sub
  1620. WifiLight_RGBWLD382_Off(@)
  1621. {
  1622. my ($ledDevice, $ramp) = @_;
  1623. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD382 set off $ramp");
  1624. return WifiLight_RGBWLD382_Dim($ledDevice, 0, $ramp, '');
  1625. }
  1626. sub
  1627. WifiLight_RGBWLD382_Dim(@)
  1628. {
  1629. my ($ledDevice, $level, $ramp, $flags) = @_;
  1630. my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  1631. my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  1632. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD382 dim $level $ramp $flags");
  1633. return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
  1634. }
  1635. sub
  1636. WifiLight_RGBWLD382_setHSV(@)
  1637. {
  1638. my ($ledDevice, $hue, $sat, $val) = @_;
  1639. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  1640. my $delay = 50;
  1641. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW LD382 set h:$hue, s:$sat, v:$val");
  1642. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  1643. # apply gamma correction
  1644. my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
  1645. # color cast correction
  1646. my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
  1647. # convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
  1648. my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
  1649. my $msg = sprintf("%c%c%c%c%c%c%c", 0x31, $rr, $rg, $rb, $white, 0x00, 0x00);
  1650. #add checksum
  1651. $msg = WifiLight_RGBWLD382_Checksum($ledDevice, $msg);
  1652. # lock ll queue to prevent a bottleneck within llqueue
  1653. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  1654. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  1655. $ledDevice->{helper}->{llLock} += 1;
  1656. WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  1657. # unlock ll queue
  1658. return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  1659. }
  1660. sub
  1661. WifiLight_RGBWLD382_Checksum(@)
  1662. {
  1663. my ($ledDevice, $msg) = @_;
  1664. my $c = 0;
  1665. foreach my $w (split //, $msg)
  1666. {
  1667. $c += ord($w);
  1668. }
  1669. $c %= 0x100;
  1670. $msg .= sprintf("%c", $c);
  1671. return $msg;
  1672. }
  1673. ###############################################################################
  1674. #
  1675. # device specific controller functions LD382 aka Magic UFO
  1676. # with RGB stripe (mixed white)
  1677. #
  1678. #
  1679. ###############################################################################
  1680. sub
  1681. WifiLight_RGBLD382_On(@)
  1682. {
  1683. my ($ledDevice, $ramp) = @_;
  1684. my $delay = 50;
  1685. my $on = sprintf("%c%c%c", 0x71, 0x23, 0x94);
  1686. my $msg = sprintf("%c%c%c%c%c", 0x56, 0, 0, 0, 0xAA);
  1687. my $receiver;
  1688. WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
  1689. my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
  1690. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LD382 set on ($h, $s, $v) $ramp");
  1691. return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
  1692. }
  1693. sub
  1694. WifiLight_RGBLD382_Off(@)
  1695. {
  1696. my ($ledDevice, $ramp) = @_;
  1697. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LD382 set off $ramp");
  1698. return WifiLight_RGBLD382_Dim($ledDevice, 0, $ramp, '');
  1699. }
  1700. sub
  1701. WifiLight_RGBLD382_Dim(@)
  1702. {
  1703. my ($ledDevice, $level, $ramp, $flags) = @_;
  1704. my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  1705. my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  1706. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LD382 dim $level $ramp $flags");
  1707. return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
  1708. }
  1709. sub
  1710. WifiLight_RGBLD382_setHSV(@)
  1711. {
  1712. my ($ledDevice, $hue, $sat, $val) = @_;
  1713. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  1714. my $delay = 50;
  1715. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGB LD382 set h:$hue, s:$sat, v:$val");
  1716. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  1717. # apply gamma correction
  1718. my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
  1719. # color cast correction
  1720. my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
  1721. # convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
  1722. my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
  1723. my ($wr, $wg, $wb) = split(',', AttrVal($ledDevice->{NAME}, 'whitePoint', '1, 1, 1'));
  1724. #replace the removed part of white light and apply white balance
  1725. $rr += int(($white * $wr) + 0.5);
  1726. $rg += int(($white * $wg) + 0.5);
  1727. $rb += int(($white * $wb) + 0.5);
  1728. my $msg = sprintf("%c%c%c%c%c%c%c", 0x31, $rr, $rg, $rb, 0x00, 0x00, 0x00);
  1729. #add checksum
  1730. $msg = WifiLight_RGBWLD382_Checksum($ledDevice, $msg);
  1731. # lock ll queue to prevent a bottleneck within llqueue
  1732. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  1733. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  1734. $ledDevice->{helper}->{llLock} += 1;
  1735. WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  1736. # unlock ll queue
  1737. return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  1738. }
  1739. ###############################################################################
  1740. #
  1741. # device specific controller functions LD382A aka Magic UFO
  1742. # with RGBW stripe (RGB and white)
  1743. # LD382A is a LD382 with fw 1.0.6
  1744. #
  1745. ###############################################################################
  1746. sub
  1747. WifiLight_RGBWLD382A_On(@)
  1748. {
  1749. my ($ledDevice, $ramp) = @_;
  1750. my $delay = 50;
  1751. my $on = sprintf("%c%c%c%c", 0x71, 0x23, 0x0F, 0xA3);
  1752. # my $msg = sprintf("%c%c%c%c%c", 0x56, 0, 0, 0, 0xAA);
  1753. my $receiver;
  1754. WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
  1755. my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
  1756. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD382A set on ($h, $s, $v) $ramp");
  1757. return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
  1758. }
  1759. sub
  1760. WifiLight_RGBWLD382A_Off(@)
  1761. {
  1762. my ($ledDevice, $ramp) = @_;
  1763. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD382A set off $ramp");
  1764. return WifiLight_RGBWLD382A_Dim($ledDevice, 0, $ramp, '');
  1765. }
  1766. sub
  1767. WifiLight_RGBWLD382A_Dim(@)
  1768. {
  1769. my ($ledDevice, $level, $ramp, $flags) = @_;
  1770. my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  1771. my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  1772. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW LD382A dim $level $ramp $flags");
  1773. return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
  1774. }
  1775. sub
  1776. WifiLight_RGBWLD382A_setHSV(@)
  1777. {
  1778. my ($ledDevice, $hue, $sat, $val) = @_;
  1779. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  1780. my $delay = 50;
  1781. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW LD382A set h:$hue, s:$sat, v:$val");
  1782. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  1783. # apply gamma correction
  1784. my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
  1785. # color cast correction
  1786. my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
  1787. # convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
  1788. my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
  1789. my $msg = sprintf("%c%c%c%c%c%c%c", 0x31, $rr, $rg, $rb, $white, 0x00, 0x0F);
  1790. #add checksum
  1791. $msg = WifiLight_RGBWLD382_Checksum($ledDevice, $msg);
  1792. # lock ll queue to prevent a bottleneck within llqueue
  1793. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  1794. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  1795. $ledDevice->{helper}->{llLock} += 1;
  1796. WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  1797. # unlock ll queue
  1798. return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  1799. }
  1800. ###############################################################################
  1801. #
  1802. # device specific controller functions LD382A aka Magic UFO
  1803. # with RGB stripe (mixed white)
  1804. # LD382A is a LD382 with fw 1.0.6
  1805. #
  1806. ###############################################################################
  1807. sub
  1808. WifiLight_RGBLD382A_On(@)
  1809. {
  1810. my ($ledDevice, $ramp) = @_;
  1811. my $delay = 50;
  1812. my $on = sprintf("%c%c%c%c", 0x71, 0x23, 0x0F, 0xA3);
  1813. # my $msg = sprintf("%c%c%c%c%c", 0x56, 0, 0, 0, 0xAA);
  1814. my $receiver;
  1815. WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
  1816. my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
  1817. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LD382A set on ($h, $s, $v) $ramp");
  1818. return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
  1819. }
  1820. sub
  1821. WifiLight_RGBLD382A_Off(@)
  1822. {
  1823. my ($ledDevice, $ramp) = @_;
  1824. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LD382A set off $ramp");
  1825. return WifiLight_RGBLD382A_Dim($ledDevice, 0, $ramp, '');
  1826. }
  1827. sub
  1828. WifiLight_RGBLD382A_Dim(@)
  1829. {
  1830. my ($ledDevice, $level, $ramp, $flags) = @_;
  1831. my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  1832. my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  1833. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LD382A dim $level $ramp $flags");
  1834. return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
  1835. }
  1836. sub
  1837. WifiLight_RGBLD382A_setHSV(@)
  1838. {
  1839. my ($ledDevice, $hue, $sat, $val) = @_;
  1840. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  1841. my $delay = 50;
  1842. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGB LD382A set h:$hue, s:$sat, v:$val");
  1843. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  1844. # apply gamma correction
  1845. my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
  1846. # color cast correction
  1847. my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
  1848. # convert to device 4 channels (remaining r,g,b after substract white, white, rgb)
  1849. my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
  1850. my ($wr, $wg, $wb) = split(',', AttrVal($ledDevice->{NAME}, 'whitePoint', '1, 1, 1'));
  1851. #replace the removed part of white light and apply white balance
  1852. $rr += int(($white * $wr) + 0.5);
  1853. $rg += int(($white * $wg) + 0.5);
  1854. $rb += int(($white * $wb) + 0.5);
  1855. my $msg = sprintf("%c%c%c%c%c%c%c", 0x31, $rr, $rg, $rb, 0x00, 0x00, 0x0F);
  1856. #add checksum
  1857. $msg = WifiLight_RGBWLD382_Checksum($ledDevice, $msg);
  1858. # lock ll queue to prevent a bottleneck within llqueue
  1859. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  1860. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  1861. $ledDevice->{helper}->{llLock} += 1;
  1862. WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  1863. # unlock ll queue
  1864. return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  1865. }
  1866. ###############################################################################
  1867. #
  1868. # device specific controller functions RGB LW12
  1869. # LED Stripe controller LW12
  1870. #
  1871. #
  1872. ###############################################################################
  1873. sub
  1874. WifiLight_RGBLW12_On(@)
  1875. {
  1876. my ($ledDevice, $ramp) = @_;
  1877. my $delay = 50;
  1878. my $on = sprintf("%c%c%c", 0xCC, 0x23, 0x33);
  1879. my $msg = sprintf("%c%c%c%c%c", 0x56, 0, 0, 0, 0xAA);
  1880. my $receiver;
  1881. WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
  1882. # WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  1883. my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
  1884. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LW12 set on ($h, $s, $v) $ramp");
  1885. return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
  1886. }
  1887. #TODO set physical off: my $off = sprintf("%c%c%c", 0xCC, 0x24, 0x33);
  1888. sub
  1889. WifiLight_RGBLW12_Off(@)
  1890. {
  1891. my ($ledDevice, $ramp) = @_;
  1892. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LW12 set off $ramp");
  1893. return WifiLight_RGBLW12_Dim($ledDevice, 0, $ramp, '');
  1894. }
  1895. sub
  1896. WifiLight_RGBLW12_Dim(@)
  1897. {
  1898. my ($ledDevice, $level, $ramp, $flags) = @_;
  1899. my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  1900. my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  1901. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LW12 dim $level $ramp $flags");
  1902. return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
  1903. }
  1904. sub
  1905. WifiLight_RGBLW12_setHSV(@)
  1906. {
  1907. my ($ledDevice, $hue, $sat, $val) = @_;
  1908. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  1909. my $delay = 50;
  1910. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGB LW12 set h:$hue, s:$sat, v:$val");
  1911. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  1912. # apply gamma correction
  1913. my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
  1914. # color cast correction
  1915. my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
  1916. #new style converter with white point correction
  1917. my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
  1918. my ($wr, $wg, $wb) = split(',', AttrVal($ledDevice->{NAME}, 'whitePoint', '1, 1, 1'));
  1919. #replace the removed part of white light and apply white balance
  1920. $rr += int(($white * $wr) + 0.5);
  1921. $rg += int(($white * $wg) + 0.5);
  1922. $rb += int(($white * $wb) + 0.5);
  1923. my $msg = sprintf("%c%c%c%c%c", 0x56, $rr, $rg, $rb, 0xAA);
  1924. # lock ll queue to prevent a bottleneck within llqueue
  1925. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  1926. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  1927. $ledDevice->{helper}->{llLock} += 1;
  1928. WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  1929. # unlock ll queue
  1930. return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  1931. }
  1932. ###############################################################################
  1933. #
  1934. # device specific controller functions RGB LW12 HX001 Version
  1935. # LED Stripe controller LW12
  1936. #
  1937. #
  1938. ###############################################################################
  1939. sub
  1940. WifiLight_RGBLW12HX_On(@)
  1941. {
  1942. my ($ledDevice, $ramp) = @_;
  1943. # my $delay = 50;
  1944. # my $on = sprintf("%c%c%c", 0xCC, 0x23, 0x33);
  1945. # my $msg = sprintf("%c%c%c%c%c", 0x56, 0, 0, 0, 0xAA);
  1946. # my $receiver;
  1947. # WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
  1948. # WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  1949. my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
  1950. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LW12HX set on ($h, $s, $v) $ramp");
  1951. return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
  1952. }
  1953. sub
  1954. WifiLight_RGBLW12HX_Off(@)
  1955. {
  1956. my ($ledDevice, $ramp) = @_;
  1957. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LW12HX set off $ramp");
  1958. return WifiLight_RGBLW12HX_Dim($ledDevice, 0, $ramp, '');
  1959. }
  1960. sub
  1961. WifiLight_RGBLW12HX_Dim(@)
  1962. {
  1963. my ($ledDevice, $level, $ramp, $flags) = @_;
  1964. my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  1965. my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  1966. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBHX LW12 dim $level $ramp $flags");
  1967. return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
  1968. }
  1969. sub
  1970. WifiLight_RGBLW12HX_setHSV(@)
  1971. {
  1972. my ($ledDevice, $hue, $sat, $val) = @_;
  1973. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  1974. my $delay = 50;
  1975. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGB LW12 set h:$hue, s:$sat, v:$val");
  1976. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  1977. # apply gamma correction
  1978. my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
  1979. # color cast correction
  1980. my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
  1981. #new style converter with white point correction
  1982. my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
  1983. my ($wr, $wg, $wb) = split(',', AttrVal($ledDevice->{NAME}, 'whitePoint', '1, 1, 1'));
  1984. #replace the removed part of white light and apply white balance
  1985. $rr += int(($white * $wr) + 0.5);
  1986. $rg += int(($white * $wg) + 0.5);
  1987. $rb += int(($white * $wb) + 0.5);
  1988. my $on = ($gammaVal > 0)?1:0;
  1989. my $dim = 100;
  1990. # supported by ichichich
  1991. my @sendData = (0x9D, 0x62, 0x00, 0x01, 0x01, $on, $dim, $rr, $rg, $rb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
  1992. my $chkSum = 0xFF;
  1993. $chkSum += $_ for @sendData[3, 5..9];
  1994. unless ($chkSum == 0)
  1995. {
  1996. $chkSum %= 0xFF;
  1997. $chkSum = 0xFF if ($chkSum == 0);
  1998. }
  1999. push (@sendData, $chkSum);
  2000. for (my $i=2; $i<11; $i++)
  2001. {
  2002. my $h = ($sendData[$i] & 0xF0) + ($sendData[21-$i] >> 4);
  2003. my $l = (($sendData[$i] & 0x0F) << 4) + ($sendData[21-$i] & 0x0F);
  2004. $sendData[$i] = $h;
  2005. $sendData[21-$i] = $l;
  2006. }
  2007. my $msg = pack('C*', @sendData);
  2008. # $dbgStr = unpack("H*", $msg);
  2009. # print "lw12HX $dbgStr \n";
  2010. # lock ll queue to prevent a bottleneck within llqueue
  2011. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  2012. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  2013. $ledDevice->{helper}->{llLock} += 1;
  2014. WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  2015. # unlock ll queue
  2016. return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  2017. }
  2018. ###############################################################################
  2019. #
  2020. # device specific controller functions RGB LW12 FC Version
  2021. # LED Stripe controller LW12
  2022. #
  2023. #
  2024. ###############################################################################
  2025. sub
  2026. WifiLight_RGBLW12FC_On(@)
  2027. {
  2028. my ($ledDevice, $ramp) = @_;
  2029. my $delay = 50;
  2030. my $on = sprintf("%c%c%c%c%c%c%c%c%c", 0x7E, 0x04, 0x04, 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0xEF);
  2031. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  2032. WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
  2033. my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
  2034. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LW12FC set on ($h, $s, $v) $ramp");
  2035. return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
  2036. }
  2037. sub
  2038. WifiLight_RGBLW12FC_Off(@)
  2039. {
  2040. my ($ledDevice, $ramp) = @_;
  2041. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LW12FC set off $ramp");
  2042. return WifiLight_RGBLW12FC_Dim($ledDevice, 0, $ramp, '');
  2043. }
  2044. sub
  2045. WifiLight_RGBLW12FC_Dim(@)
  2046. {
  2047. my ($ledDevice, $level, $ramp, $flags) = @_;
  2048. my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  2049. my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  2050. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LW12FC dim $level $ramp $flags");
  2051. return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 100, undef);
  2052. }
  2053. sub
  2054. WifiLight_RGBLW12FC_setHSV(@)
  2055. {
  2056. my ($ledDevice, $hue, $sat, $val) = @_;
  2057. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  2058. my $delay = 50;
  2059. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGB LW12FC set h:$hue, s:$sat, v:$val");
  2060. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  2061. # apply gamma correction
  2062. my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
  2063. # color cast correction
  2064. my $h = $ledDevice->{helper}->{COLORMAP}[$hue];
  2065. # new style converter with white point correction
  2066. my ($rr, $rg, $rb, $white) = WifiLight_HSV2fourChannel($h, $sat, $gammaVal);
  2067. my ($wr, $wg, $wb) = split(',', AttrVal($ledDevice->{NAME}, 'whitePoint', '1, 1, 1'));
  2068. # replace the removed part of white light and apply white balance
  2069. $rr += int(($white * $wr) + 0.5);
  2070. $rg += int(($white * $wg) + 0.5);
  2071. $rb += int(($white * $wb) + 0.5);
  2072. my $on = ($gammaVal > 0)?1:0;
  2073. my $dim = 100;
  2074. my $msg = sprintf("%c%c%c%c%c%c%c%c%c", 0x7E, 0x07, 0x05, 0x03, $rr, $rg, $rb, 0x00, 0xEF);
  2075. # lock ll queue to prevent a bottleneck within llqueue
  2076. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  2077. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  2078. $ledDevice->{helper}->{llLock} += 1;
  2079. WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  2080. # unlock ll queue
  2081. return WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  2082. }
  2083. ###############################################################################
  2084. #
  2085. # device specific controller functions White SENGLED
  2086. # E27 LED Bulb with
  2087. #
  2088. #
  2089. ###############################################################################
  2090. sub
  2091. WifiLight_WhiteSENGLED_On(@)
  2092. {
  2093. my ($ledDevice, $ramp) = @_;
  2094. # my $delay = 50;
  2095. # my $on = sprintf("%c%c%c%c%c%c%c%c%c", 0x7E, 0x04, 0x04, 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0xEF);
  2096. # my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  2097. # WifiLight_LowLevelCmdQueue_Add($ledDevice, $on, $receiver, $delay);
  2098. my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
  2099. Log3 ($ledDevice, 3, "$ledDevice->{NAME} White SENGLED set on ($h, $s, $v) $ramp");
  2100. return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 100, undef);
  2101. }
  2102. sub
  2103. WifiLight_WhiteSENGLED_Off(@)
  2104. {
  2105. my ($ledDevice, $ramp) = @_;
  2106. Log3 ($ledDevice, 3, "$ledDevice->{NAME} White SENGLED set off $ramp");
  2107. return WifiLight_WhiteSENGLED_Dim($ledDevice, 0, $ramp, '');
  2108. }
  2109. sub
  2110. WifiLight_WhiteSENGLED_Dim(@)
  2111. {
  2112. my ($ledDevice, $level, $ramp, $flags) = @_;
  2113. # my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  2114. # my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  2115. Log3 ($ledDevice, 3, "$ledDevice->{NAME} White SENGLED dim $level $ramp $flags");
  2116. return WifiLight_HSV_Transition($ledDevice, 0, 0, $level, $ramp, $flags, 100, undef);
  2117. }
  2118. sub
  2119. WifiLight_WhiteSENGLED_setHSV(@)
  2120. {
  2121. my ($ledDevice, $hue, $sat, $val, $isLast) = @_;
  2122. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  2123. my $delay = 50;
  2124. Log3 ($ledDevice, 4, "$ledDevice->{NAME} White SENGLED set h:$hue, s:$sat, v:$val");
  2125. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  2126. # apply gamma correction
  2127. my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
  2128. my @remote = split(/\./, $ledDevice->{helper}->{SOCKET}->peerhost());
  2129. # intro
  2130. my $msg = sprintf("%c%c%c%c%c", 0x0d, 0x00, 0x02, 0x00, 0x01);
  2131. # sender, lazy 0x00
  2132. $msg .= sprintf("%c%c%c%c", 0x00, 0x00, 0x00, 0x00);
  2133. # destinations
  2134. $msg .= sprintf("%c%c%c%c", $remote[0], $remote[1], $remote[2], $remote[3] );
  2135. # sender, lazy 0x00
  2136. $msg .= sprintf("%c%c%c%c", 0x00, 0x00, 0x00, 0x00);
  2137. # destinations
  2138. $msg .= sprintf("%c%c%c%c", $remote[0], $remote[1], $remote[2], $remote[3] );
  2139. # intro 2
  2140. $msg .= sprintf("%c%c%c%c%c%c", 0x01, 0x00, 0x01, 0x00, 0x00, 0x00);
  2141. # cmd level
  2142. $msg .= sprintf("%c%c", $gammaVal, 0x64);
  2143. # for safety of tranmission (udp): repeat cmd if its stand-alone or first or last in transition
  2144. my $repeat = ($isLast)?3:1;
  2145. for (my $i=0; $i<$repeat; $i++)
  2146. {
  2147. # lock ll queue to prevent a bottleneck within llqueue
  2148. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  2149. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  2150. $ledDevice->{helper}->{llLock} += 1;
  2151. WifiLight_LowLevelCmdQueue_Add($ledDevice, $msg, $receiver, $delay);
  2152. # unlock ll queue after complete cmd is send
  2153. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  2154. }
  2155. return undef;
  2156. }
  2157. ###############################################################################
  2158. #
  2159. # device specific controller functions RGB
  2160. # LED Stripe or bulb, no white, controller V2
  2161. #
  2162. ###############################################################################
  2163. sub
  2164. WifiLight_RGB_Pair(@)
  2165. {
  2166. my ($ledDevice, $numSeconds) = @_;
  2167. $numSeconds = 3 if (($numSeconds || 0) == 0);
  2168. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LED slot $ledDevice->{SLOT} pair $numSeconds");
  2169. # find my slot and get my group-all-on cmd
  2170. my $ctrl = "\x25\x00\x55";
  2171. for (my $i = 0; $i < $numSeconds; $i++)
  2172. {
  2173. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
  2174. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
  2175. }
  2176. return undef;
  2177. }
  2178. sub
  2179. WifiLight_RGB_UnPair(@)
  2180. {
  2181. my ($ledDevice) = @_;
  2182. my $numSeconds = 8;
  2183. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB LED slot $ledDevice->{SLOT} unpair $numSeconds");
  2184. # find my slot and get my group-all-on cmd
  2185. my $ctrl = "\x25\x00\x55";
  2186. for (my $i = 0; $i < $numSeconds; $i++)
  2187. {
  2188. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
  2189. }
  2190. return undef;
  2191. }
  2192. sub
  2193. WifiLight_RGB_Sync(@)
  2194. {
  2195. my ($ledDevice) = @_;
  2196. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  2197. my $delay = 100;
  2198. $ledDevice->{helper}->{whiteLevel} =9;
  2199. $ledDevice->{helper}->{colorLevel} =9;
  2200. $ledDevice->{helper}->{colorValue} =127;
  2201. $ledDevice->{helper}->{mode} =2; # mode 0: off, 1: mixed "white", 2: color
  2202. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x22\x00\x55", $receiver, 500); # on
  2203. for (my $i = 0; $i < 22; $i++) {
  2204. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode up (to "pure white" ;-)
  2205. }
  2206. for (my $i = 0; $i < 10; $i++) {
  2207. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up (to "pure white" ;-)
  2208. }
  2209. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x20\x7F\x55", $receiver, $delay); # color yellow (auto jump to mode 2)
  2210. for (my $i = 0; $i < 10; $i++) {
  2211. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up (yellow max brightness)
  2212. }
  2213. WifiLight_setHSV_Readings($ledDevice, 60, 100, 100) if $init_done;
  2214. return undef;
  2215. }
  2216. sub
  2217. WifiLight_RGB_On(@)
  2218. {
  2219. my ($ledDevice, $ramp) = @_;
  2220. my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "40,100,100"));
  2221. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB slot $ledDevice->{SLOT} set on ($h, $s, $v) $ramp");
  2222. return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 500, undef);
  2223. }
  2224. sub
  2225. WifiLight_RGB_Off(@)
  2226. {
  2227. my ($ledDevice, $ramp) = @_;
  2228. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB slot $ledDevice->{SLOT} set off $ramp");
  2229. return WifiLight_RGB_Dim($ledDevice, 0, $ramp, '');
  2230. #TODO remove if tested
  2231. #return WifiLight_HSV_Transition($ledDevice, 0, 100, 0, $ramp, undef, 500, undef);
  2232. }
  2233. sub
  2234. WifiLight_RGB_Dim(@)
  2235. {
  2236. my ($ledDevice, $level, $ramp, $flags) = @_;
  2237. my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  2238. my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  2239. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGB slot $ledDevice->{SLOT} dim $level $ramp $flags");
  2240. return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 500, undef);
  2241. }
  2242. sub
  2243. WifiLight_RGB_setHSV(@)
  2244. {
  2245. my ($ledDevice, $hue, $sat, $val) = @_;
  2246. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGB slot $ledDevice->{SLOT} set h:$hue, s:$sat, v:$val");
  2247. $sat = 100;
  2248. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  2249. # convert to device specs
  2250. my ($cv, $cl, $wl) = WifiLight_RGBW1_ColorConverter($ledDevice, $hue, $sat, $val);
  2251. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGB slot $ledDevice->{SLOT} set levels: $cv, $cl, $wl");
  2252. return WifiLight_RGB_setLevels($ledDevice, $cv, $cl, $wl);
  2253. }
  2254. sub
  2255. WifiLight_RGB_setLevels(@)
  2256. {
  2257. my ($ledDevice, $cv, $cl, $wl) = @_;
  2258. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  2259. my $delay = 100;
  2260. my $lock = 0;
  2261. # mode 0: off, 1: mixed "white", 2: color
  2262. # lock ll queue to prevent a bottleneck within llqueue
  2263. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  2264. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  2265. if ((($ledDevice->{helper}->{colorValue} != $cv) && ($cl > 0)) || ($ledDevice->{helper}->{colorLevel} != $cl) || ($ledDevice->{helper}->{whiteLevel} != $wl))
  2266. {
  2267. $ledDevice->{helper}->{llLock} += 1;
  2268. $lock = 1;
  2269. }
  2270. # need to touch color value (only if visible) or color level ?
  2271. if ((($ledDevice->{helper}->{colorValue} != $cv) && ($cl > 0)) || $ledDevice->{helper}->{colorLevel} != $cl)
  2272. {
  2273. # if color all off switch on
  2274. if ($ledDevice->{helper}->{mode} == 0)
  2275. {
  2276. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x22\x00\x55", $receiver, $delay); # switch on
  2277. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x20".chr($cv)."\x55", $receiver, $delay); # set color
  2278. $ledDevice->{helper}->{colorValue} = $cv;
  2279. $ledDevice->{helper}->{colorLevel} = 1;
  2280. $ledDevice->{helper}->{mode} = 2;
  2281. }
  2282. elsif ($ledDevice->{helper}->{mode} == 1)
  2283. {
  2284. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x20".chr($cv)."\x55", $receiver, $delay); # set color
  2285. $ledDevice->{helper}->{colorValue} = $cv;
  2286. $ledDevice->{helper}->{mode} = 2;
  2287. }
  2288. else
  2289. {
  2290. $ledDevice->{helper}->{colorValue} = $cv;
  2291. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x20".chr($cv)."\x55", $receiver, $delay); # set color
  2292. }
  2293. # cl decrease
  2294. if ($ledDevice->{helper}->{colorLevel} > $cl)
  2295. {
  2296. for (my $i=$ledDevice->{helper}->{colorLevel}; $i > $cl; $i--)
  2297. {
  2298. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x24\x00\x55", $receiver, $delay); # brightness down
  2299. $ledDevice->{helper}->{colorLevel} = $i - 1;
  2300. }
  2301. if ($cl == 0)
  2302. {
  2303. # need to switch off color
  2304. # if no white is required and no white is active we can must entirely switch off
  2305. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x21\x00\x55", $receiver, $delay); # switch off
  2306. $ledDevice->{helper}->{colorLevel} = 0;
  2307. $ledDevice->{helper}->{mode} = 0;
  2308. }
  2309. }
  2310. # cl inrease
  2311. if ($ledDevice->{helper}->{colorLevel} < $cl)
  2312. {
  2313. for (my $i=$ledDevice->{helper}->{colorLevel}; $i < $cl; $i++)
  2314. {
  2315. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # brightness up
  2316. $ledDevice->{helper}->{colorLevel} = $i + 1;
  2317. }
  2318. }
  2319. }
  2320. # unlock ll queue
  2321. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1) if $lock;
  2322. return undef;
  2323. }
  2324. ###############################################################################
  2325. #
  2326. # device specific controller functions RGBW1
  2327. # LED Stripe with extra white led, controller V2, bridge V2|bridge V3
  2328. #
  2329. #
  2330. ###############################################################################
  2331. sub
  2332. WifiLight_RGBW1_Pair(@)
  2333. {
  2334. my ($ledDevice, $numSeconds) = @_;
  2335. $numSeconds = 3 if (($numSeconds || 0) == 0);
  2336. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW1 LED slot $ledDevice->{SLOT} pair $numSeconds");
  2337. # find my slot and get my group-all-on cmd
  2338. my $ctrl = "\x25\x00\x55";
  2339. for (my $i = 0; $i < $numSeconds; $i++)
  2340. {
  2341. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
  2342. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
  2343. }
  2344. return undef;
  2345. }
  2346. sub
  2347. WifiLight_RGBW1_UnPair(@)
  2348. {
  2349. my ($ledDevice) = @_;
  2350. my $numSeconds = 8;
  2351. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW1 LED slot $ledDevice->{SLOT} unpair $numSeconds");
  2352. # find my slot and get my group-all-on cmd
  2353. my $ctrl = "\x25\x00\x55";
  2354. for (my $i = 0; $i < $numSeconds; $i++)
  2355. {
  2356. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
  2357. }
  2358. return undef;
  2359. }
  2360. sub
  2361. WifiLight_RGBW1_Sync(@)
  2362. {
  2363. my ($ledDevice) = @_;
  2364. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  2365. my $delay = 250;
  2366. $ledDevice->{helper}->{whiteLevel} =9;
  2367. $ledDevice->{helper}->{colorLevel} =9;
  2368. $ledDevice->{helper}->{colorValue} =170;
  2369. $ledDevice->{helper}->{mode} =3; # mode 0: c:off, w:off; 1: c:on, w:off; 2: c:off, w:on; 3: c:on, w:on
  2370. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x22\x00\x55", $receiver, 500); # on
  2371. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x22\x00\x55", $receiver, $delay); # on
  2372. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x20\xAA\x55", $receiver, $delay); # color red (auto jump to mode 1 except we are mode 3)
  2373. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode down
  2374. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode down (now we are for sure in mode 1)
  2375. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #1
  2376. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #2
  2377. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #3
  2378. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #4
  2379. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #5
  2380. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #6
  2381. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #7
  2382. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #8
  2383. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #9 (highest dim-level color red)
  2384. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x27\x00\x55", $receiver, $delay); # mode up (pure white)
  2385. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #1
  2386. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #2
  2387. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #3
  2388. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #4
  2389. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #5
  2390. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #6
  2391. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #7
  2392. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #8
  2393. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # dim up #9 (highest dim-level white)
  2394. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x27\x00\x55", $receiver, $delay); # mode up (white and red at highest level: bright warm light)
  2395. WifiLight_setHSV_Readings($ledDevice, 0, 50, 100) if $init_done;
  2396. return undef;
  2397. }
  2398. sub
  2399. WifiLight_RGBW1_On(@)
  2400. {
  2401. my ($ledDevice, $ramp) = @_;
  2402. my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
  2403. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW1 slot $ledDevice->{SLOT} set on ($h, $s, $v) $ramp");
  2404. return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 1000, undef);
  2405. }
  2406. sub
  2407. WifiLight_RGBW1_Off(@)
  2408. {
  2409. my ($ledDevice, $ramp) = @_;
  2410. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW1 slot $ledDevice->{SLOT} set off $ramp");
  2411. return WifiLight_RGBW1_Dim($ledDevice, 0, $ramp, '');
  2412. }
  2413. sub
  2414. WifiLight_RGBW1_Dim(@)
  2415. {
  2416. my ($ledDevice, $level, $ramp, $flags) = @_;
  2417. my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  2418. my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  2419. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW1 slot $ledDevice->{SLOT} dim $level $ramp $flags");
  2420. return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 1000, undef);
  2421. }
  2422. sub
  2423. WifiLight_RGBW1_setHSV(@)
  2424. {
  2425. my ($ledDevice, $hue, $sat, $val) = @_;
  2426. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW1 slot $ledDevice->{SLOT} set h:$hue, s:$sat, v:$val");
  2427. WifiLight_setHSV_Readings($ledDevice, $hue, $sat, $val);
  2428. # convert to device specs
  2429. my ($cv, $cl, $wl) = WifiLight_RGBW1_ColorConverter($ledDevice, $hue, $sat, $val);
  2430. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW1 slot $ledDevice->{SLOT} set levels: $cv, $cl, $wl");
  2431. return WifiLight_RGBW1_setLevels($ledDevice, $cv, $cl, $wl);
  2432. }
  2433. sub
  2434. WifiLight_RGBW1_setLevels(@)
  2435. {
  2436. my ($ledDevice, $cv, $cl, $wl) = @_;
  2437. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  2438. my $delay = 250;
  2439. my $lock = 0;
  2440. # need to touch color value or color level?
  2441. # yes
  2442. # is color visible ? (we are in mode 1 or 3)
  2443. # yes: adjust color!, requ level = 1 if cl = 0; new level 0 ? yes: mode 0 if wl == 0 else Mode = 1 (if coming from 0 or 1 then wl =1)
  2444. # no:
  2445. # will we need color ?
  2446. # yes: go into mode #1, (cl jumps to 1)
  2447. # lock ll queue to prevent a bottleneck within llqueue
  2448. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  2449. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  2450. if ((($ledDevice->{helper}->{colorValue} != $cv) && ($cl > 0)) || ($ledDevice->{helper}->{colorLevel} != $cl) || ($ledDevice->{helper}->{whiteLevel} != $wl))
  2451. {
  2452. $ledDevice->{helper}->{llLock} += 1;
  2453. $lock = 1;
  2454. }
  2455. # need to touch color value (only if visible) or color level ?
  2456. if ((($ledDevice->{helper}->{colorValue} != $cv) && ($cl > 0)) || $ledDevice->{helper}->{colorLevel} != $cl)
  2457. {
  2458. # if color all off switch on
  2459. if ($ledDevice->{helper}->{mode} == 0)
  2460. {
  2461. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x22\x00\x55", $receiver, $delay); # switch on
  2462. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode down: 3 > 2 || 2 > 1
  2463. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode down: 2 > 1 || 1 > 1
  2464. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x20".chr($cv)."\x55", $receiver, $delay); # set color
  2465. $ledDevice->{helper}->{colorValue} = $cv;
  2466. $ledDevice->{helper}->{colorLevel} = 1;
  2467. $ledDevice->{helper}->{mode} = 1;
  2468. }
  2469. elsif ($ledDevice->{helper}->{mode} == 2)
  2470. {
  2471. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x27\x00\x55", $receiver, $delay); # mode up: 2 > 3
  2472. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x20".chr($cv)."\x55", $receiver, $delay); # set color
  2473. $ledDevice->{helper}->{colorValue} = $cv;
  2474. $ledDevice->{helper}->{colorLevel} = 1;
  2475. $ledDevice->{helper}->{mode} = 3;
  2476. }
  2477. else
  2478. {
  2479. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x20".chr($cv)."\x55", $receiver, $delay); # set color
  2480. $ledDevice->{helper}->{colorValue} = $cv;
  2481. }
  2482. # color level decrease
  2483. if ($ledDevice->{helper}->{colorLevel} > $cl)
  2484. {
  2485. for (my $i=$ledDevice->{helper}->{colorLevel}; $i > $cl; $i--)
  2486. {
  2487. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x24\x00\x55", $receiver, $delay); # brightness down
  2488. $ledDevice->{helper}->{colorLevel} = $i - 1;
  2489. }
  2490. if ($cl == 0)
  2491. {
  2492. # need to switch off color
  2493. # if no white is required and no white is active switch off
  2494. if (($wl == 0) && ($ledDevice->{helper}->{mode} == 1))
  2495. {
  2496. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x21\x00\x55", $receiver, $delay); # switch off
  2497. $ledDevice->{helper}->{colorLevel} = 0;
  2498. $ledDevice->{helper}->{mode} = 0;
  2499. }
  2500. # if white is required, goto mode 2: pure white
  2501. if (($wl > 0) || ($ledDevice->{helper}->{mode} == 2) || ($ledDevice->{helper}->{mode} == 3))
  2502. {
  2503. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x27\x00\x55", $receiver, $delay) if ($ledDevice->{helper}->{mode} == 1) ; # mode up
  2504. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay) if ($ledDevice->{helper}->{mode} == 3) ; # mode down
  2505. $ledDevice->{helper}->{colorLevel} = 0;
  2506. $ledDevice->{helper}->{whiteLevel} = 1 if ($ledDevice->{helper}->{mode} == 1);
  2507. $ledDevice->{helper}->{mode} = 2;
  2508. }
  2509. }
  2510. }
  2511. if ($ledDevice->{helper}->{colorLevel} < $cl)
  2512. {
  2513. for (my $i=$ledDevice->{helper}->{colorLevel}; $i < $cl; $i++)
  2514. {
  2515. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # brightness up
  2516. $ledDevice->{helper}->{colorLevel} = $i + 1;
  2517. }
  2518. }
  2519. }
  2520. # need to adjust white level ?
  2521. if ($ledDevice->{helper}->{whiteLevel} != $wl)
  2522. {
  2523. # white off but need adjustment ? set it on..
  2524. # color processing is finished, so if we are in mode 0, no color required. go to mode 2: pure white
  2525. if ($ledDevice->{helper}->{mode} == 0)
  2526. {
  2527. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x22\x00\x55", $receiver, $delay); # switch on
  2528. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode down (3 -> 2 || 2 -> 1)
  2529. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode down (2 -> 1 || 1 -> 1)
  2530. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x27\x00\x55", $receiver, $delay); # mode up (1 -> 2)
  2531. $ledDevice->{helper}->{whiteLevel} = 1;
  2532. $ledDevice->{helper}->{mode} = 2;
  2533. }
  2534. # color processing is finished, so if we are at mode 1 color is required. go to mode 2
  2535. if ($ledDevice->{helper}->{mode} == 1)
  2536. {
  2537. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x27\x00\x55", $receiver, $delay); # mode up (1 -> 2)
  2538. $ledDevice->{helper}->{whiteLevel} = 1;
  2539. $ledDevice->{helper}->{mode} = 2;
  2540. }
  2541. # temporary go to mode 2 while maintain white level
  2542. if ($ledDevice->{helper}->{mode} == 3)
  2543. {
  2544. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode down (3 -> 2)
  2545. $ledDevice->{helper}->{mode} = 2;
  2546. }
  2547. # white level inrease
  2548. for (my $i=$ledDevice->{helper}->{whiteLevel}; $i < $wl; $i++)
  2549. {
  2550. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x23\x00\x55", $receiver, $delay); # brightness up
  2551. $ledDevice->{helper}->{whiteLevel} = $i + 1;
  2552. }
  2553. # white level decrease
  2554. if ($ledDevice->{helper}->{whiteLevel} > $wl)
  2555. {
  2556. for (my $i=$ledDevice->{helper}->{whiteLevel}; $i > $wl; $i--)
  2557. {
  2558. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x24\x00\x55", $receiver, $delay); # brightness down
  2559. $ledDevice->{helper}->{whiteLevel} = $i - 1;
  2560. }
  2561. }
  2562. # assume we are at mode 2, finishing to correct mode
  2563. if (($wl == 0) && ($cl == 0))
  2564. {
  2565. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x21\x00\x55", $receiver, $delay); # switch off
  2566. $ledDevice->{helper}->{whiteLevel} = 0;
  2567. $ledDevice->{helper}->{mode} = 0;
  2568. }
  2569. if (($wl == 0) && ($cl > 0))
  2570. {
  2571. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x28\x00\x55", $receiver, $delay); # mode down (2 -> 1)
  2572. $ledDevice->{helper}->{whiteLevel} = 0;
  2573. $ledDevice->{helper}->{mode} = 1;
  2574. }
  2575. if (($wl > 0) && ($cl > 0))
  2576. {
  2577. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x27\x00\x55", $receiver, $delay); # mode up (2 -> 3)
  2578. $ledDevice->{helper}->{mode} = 3;
  2579. }
  2580. }
  2581. # unlock ll queue
  2582. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1) if $lock;
  2583. return undef;
  2584. }
  2585. sub
  2586. WifiLight_RGBW1_ColorConverter(@)
  2587. {
  2588. my ($ledDevice, $h, $s, $v) = @_;
  2589. my $color = $ledDevice->{helper}->{COLORMAP}[$h % 360];
  2590. # there are 0..9 dim level, setup correction
  2591. my $valueSpread = 100/9;
  2592. my $totalVal = int(($v / $valueSpread) +0.5);
  2593. # saturation 100..50: color full, white increase. 50..0 white full, color decrease
  2594. my $colorVal = ($s >= 50) ? $totalVal : int(($s / 50 * $totalVal) +0.5);
  2595. my $whiteVal = ($s >= 50) ? int(((100-$s) / 50 * $totalVal) +0.5) : $totalVal;
  2596. return ($color, $colorVal, $whiteVal);
  2597. }
  2598. ###############################################################################
  2599. #
  2600. # device specific functions RGBW2 bulb
  2601. # RGB white, only bridge V3
  2602. #
  2603. #
  2604. ###############################################################################
  2605. sub
  2606. WifiLight_RGBW2_Pair(@)
  2607. {
  2608. my ($ledDevice, $numSeconds) = @_;
  2609. $numSeconds = 3 if (($numSeconds || 0) == 0);
  2610. my @bulbCmdsOn = ("\x45", "\x47", "\x49", "\x4B");
  2611. Log3 ($ledDevice, 3, "$ledDevice->{NAME}, $ledDevice->{LEDTYPE} at $ledDevice->{CONNECTION}, slot $ledDevice->{SLOT}: pair $numSeconds");
  2612. # find my slot and get my group-all-on cmd
  2613. my $ctrl = @bulbCmdsOn[$ledDevice->{SLOT} -5]."\x00\x55";
  2614. for (my $i = 0; $i < $numSeconds; $i++)
  2615. {
  2616. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
  2617. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
  2618. }
  2619. return undef;
  2620. }
  2621. sub
  2622. WifiLight_RGBW2_UnPair(@)
  2623. {
  2624. my ($ledDevice, $numSeconds, $releaseFromSlot) = @_;
  2625. $numSeconds = 5;
  2626. my @bulbCmdsOn = ("\x45", "\x47", "\x49", "\x4B");
  2627. Log3 ($ledDevice, 3, "$ledDevice->{NAME}, $ledDevice->{LEDTYPE} at $ledDevice->{CONNECTION}, slot $ledDevice->{SLOT}: unpair $numSeconds");
  2628. # find my slot and get my group-all-on cmd
  2629. my $ctrl = @bulbCmdsOn[$ledDevice->{SLOT} -5]."\x00\x55";
  2630. for (my $i = 0; $i < $numSeconds; $i++)
  2631. {
  2632. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 250, undef, undef);
  2633. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 250, undef, undef);
  2634. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 250, undef, undef);
  2635. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 250, undef, undef);
  2636. }
  2637. return undef;
  2638. }
  2639. sub
  2640. WifiLight_RGBW2_Sync(@)
  2641. {
  2642. my ($ledDevice) = @_;
  2643. # force new settings
  2644. $ledDevice->{helper}->{mode} = -1;
  2645. $ledDevice->{helper}->{colorValue} = -1;
  2646. $ledDevice->{helper}->{colorLevel} = -1;
  2647. $ledDevice->{helper}->{whiteLevel} = -1;
  2648. return undef;
  2649. }
  2650. sub
  2651. WifiLight_RGBW2_On(@)
  2652. {
  2653. my ($ledDevice, $ramp) = @_;
  2654. my ($h, $s, $v) = split(',', AttrVal($ledDevice->{NAME}, "defaultColor", "0,0,100"));
  2655. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW2 slot $ledDevice->{SLOT} set on ($h, $s, $v) $ramp");
  2656. return WifiLight_HSV_Transition($ledDevice, $h, $s, $v, $ramp, '', 200, undef);
  2657. }
  2658. sub
  2659. WifiLight_RGBW2_Off(@)
  2660. {
  2661. my ($ledDevice, $ramp) = @_;
  2662. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW2 slot $ledDevice->{SLOT} set off $ramp");
  2663. return WifiLight_RGBW2_Dim($ledDevice, 0, $ramp, '');
  2664. #TODO remove if tested
  2665. #return WifiLight_HSV_Transition($ledDevice, 0, 0, 0, $ramp, undef, 500, undef);
  2666. }
  2667. sub
  2668. WifiLight_RGBW2_Dim(@)
  2669. {
  2670. my ($ledDevice, $level, $ramp, $flags) = @_;
  2671. my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  2672. my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  2673. Log3 ($ledDevice, 3, "$ledDevice->{NAME} RGBW2 slot $ledDevice->{SLOT} dim $level $ramp ". $flags || '');
  2674. return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 200, undef);
  2675. }
  2676. sub
  2677. WifiLight_RGBW2_setHSV(@)
  2678. {
  2679. my ($ledDevice, $hue, $sat, $val, $isLast) = @_;
  2680. my ($cl, $wl);
  2681. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  2682. my $delay = 100;
  2683. my $cv = $ledDevice->{helper}->{COLORMAP}[$hue % 360];
  2684. # apply gamma correction
  2685. my $gammaVal = $ledDevice->{helper}->{GAMMAMAP}[$val];
  2686. # mode 0 = off, 1 = color, 2 = white
  2687. # brightness 2..27 (x02..x1b) | 25
  2688. my $cf = 100 / 26;
  2689. my $cb = int(($gammaVal / $cf) + 0.5);
  2690. $cb += ($cb > 0)?1:0;
  2691. if ($sat < 20)
  2692. {
  2693. $wl = $cb;
  2694. $cl = 0;
  2695. WifiLight_setHSV_Readings($ledDevice, $hue, 0, $val);
  2696. }
  2697. else
  2698. {
  2699. $cl = $cb;
  2700. $wl = 0;
  2701. WifiLight_setHSV_Readings($ledDevice, $hue, 100, $val);
  2702. }
  2703. return WifiLight_RGBW2_setLevelsFast($ledDevice, $receiver, $cv, $cl, $wl) unless ($isLast);
  2704. return WifiLight_RGBW2_setLevelsSafe($ledDevice, $receiver, $cv, $cl, $wl);
  2705. }
  2706. # repeatly send out a full size cmd
  2707. # the last cmd in a transition or if it is stand alone
  2708. sub
  2709. WifiLight_RGBW2_setLevelsSafe(@)
  2710. {
  2711. my ($ledDevice, $receiver, $cv, $cl, $wl) = @_;
  2712. my $delay = 100;
  2713. my @bulbCmdsOn = ("\x45", "\x47", "\x49", "\x4B");
  2714. my @bulbCmdsOff = ("\x46", "\x48", "\x4A", "\x4C");
  2715. my @bulbCmdsWT = ("\xC5", "\xC7", "\xC9", "\xCB");
  2716. Log3 ($ledDevice, 4, "$ledDevice->{NAME} RGBW2 slot $ledDevice->{SLOT} set safe levels");
  2717. Log3 ($ledDevice, 5, "$ledDevice->{NAME} RGBW2 slot $ledDevice->{SLOT} lock queue ".$ledDevice->{helper}->{llLock});
  2718. my @cmd = ();
  2719. # about switching off. dim to prevent a flash if switched on again
  2720. if (($wl == 0) && ($cl == 0) && ($ledDevice->{helper}->{mode} != 0))
  2721. {
  2722. $ledDevice->{helper}->{llLock} += 1; # lock ...
  2723. WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOn[$ledDevice->{SLOT} -5]."\x00\x55", $receiver, $delay); # group on
  2724. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x4E\x02\x55", $receiver, $delay); # brightness
  2725. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1); # ... unlock
  2726. }
  2727. if (($wl == 0) && ($cl == 0))
  2728. {
  2729. push (@cmd, @bulbCmdsOff[$ledDevice->{SLOT} -5]."\x00\x55");
  2730. $ledDevice->{helper}->{whiteLevel} = 0;
  2731. $ledDevice->{helper}->{colorLevel} = 0;
  2732. $ledDevice->{helper}->{mode} = 0; # group off
  2733. }
  2734. elsif ($wl > 0)
  2735. {
  2736. push (@cmd, @bulbCmdsOn[$ledDevice->{SLOT} -5]."\x00\x55");
  2737. push (@cmd, @bulbCmdsWT[$ledDevice->{SLOT} -5]."\x00\x55");
  2738. push (@cmd, "\x4E".chr($wl)."\x55");
  2739. $ledDevice->{helper}->{whiteLevel} = $wl;
  2740. $ledDevice->{helper}->{colorLevel} = 0;
  2741. $ledDevice->{helper}->{mode} = 2; # white
  2742. }
  2743. elsif ($cl > 0)
  2744. {
  2745. push (@cmd, @bulbCmdsOn[$ledDevice->{SLOT} -5]."\x00\x55");
  2746. push (@cmd, "\x40".chr($cv)."\x55"); # color
  2747. push (@cmd, "\x4E".chr($cl)."\x55"); # brightness
  2748. $ledDevice->{helper}->{whiteLevel} = 0;
  2749. $ledDevice->{helper}->{colorLevel} = $cl;
  2750. $ledDevice->{helper}->{colorValue} = $cv;
  2751. $ledDevice->{helper}->{mode} = 1; # color
  2752. }
  2753. # repeat it three times
  2754. for (my $i=0; $i<3; $i++)
  2755. {
  2756. # lock ll queue to prevent a bottleneck within llqueue
  2757. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  2758. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  2759. $ledDevice->{helper}->{llLock} += 1;
  2760. WifiLight_LowLevelCmdQueue_Add($ledDevice, $_, $receiver, $delay) foreach (@cmd);
  2761. # unlock ll queue after complete cmd is send
  2762. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  2763. }
  2764. return undef;
  2765. }
  2766. # classic optimized version, used by fast color transitions
  2767. sub
  2768. WifiLight_RGBW2_setLevelsFast(@)
  2769. {
  2770. my ($ledDevice, $receiver, $cv, $cl, $wl) = @_;
  2771. my $delay = 100;
  2772. my @bulbCmdsOn = ("\x45", "\x47", "\x49", "\x4B");
  2773. my @bulbCmdsOff = ("\x46", "\x48", "\x4A", "\x4C");
  2774. my @bulbCmdsWT = ("\xC5", "\xC7", "\xC9", "\xCB");
  2775. return if (($ledDevice->{helper}->{colorValue} == $cv) && ($ledDevice->{helper}->{colorLevel} == $cl) && ($ledDevice->{helper}->{whiteLevel} == $wl));
  2776. # lock ll queue to prevent a bottleneck within llqueue
  2777. # in cases where the high level queue fills the low level queue (which should not be interrupted) faster then it is processed (send out)
  2778. # this lock will cause the hlexec intentionally drop frames which can safely be done because there are further frames for processing avialable
  2779. $ledDevice->{helper}->{llLock} += 1;
  2780. Log3 ($ledDevice, 5, "$ledDevice->{NAME} RGBW2 slot $ledDevice->{SLOT} lock queue ".$ledDevice->{helper}->{llLock});
  2781. if (($wl == 0) && ($cl == 0) && ($ledDevice->{helper}->{mode} != 0))
  2782. {
  2783. WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOff[$ledDevice->{SLOT} -5]."\x00\x55", $receiver, $delay);
  2784. $ledDevice->{helper}->{whiteLevel} = 0;
  2785. $ledDevice->{helper}->{colorLevel} = 0;
  2786. $ledDevice->{helper}->{mode} = 0; # group off
  2787. }
  2788. else
  2789. {
  2790. WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOn[$ledDevice->{SLOT} -5]."\x00\x55", $receiver, $delay); # group on
  2791. # WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOn[$ledDevice->{SLOT} -5]."\x00\x55", $receiver, $delay) if (($wl > 0) || ($cl > 0)); # group on
  2792. if (($wl > 0) && ($ledDevice->{helper}->{mode} == 2)) # already white
  2793. {
  2794. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x4E".chr($wl)."\x55", $receiver, $delay) if ($ledDevice->{helper}->{whiteLevel} != $wl); # brightness
  2795. }
  2796. elsif (($wl > 0) && ($ledDevice->{helper}->{mode} != 2)) # not white
  2797. {
  2798. WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsWT[$ledDevice->{SLOT} -5]."\x00\x55", $receiver, $delay); # white
  2799. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x4E".chr($wl)."\x55", $receiver, $delay); # brightness
  2800. $ledDevice->{helper}->{mode} = 2; # white
  2801. }
  2802. elsif (($cl > 0) && ($ledDevice->{helper}->{mode} == 1)) # already color
  2803. {
  2804. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x4E".chr($cl)."\x55", $receiver, $delay) if ($ledDevice->{helper}->{colorLevel} != $cl); # brightness
  2805. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x40".chr($cv)."\x55", $receiver, $delay) if ($ledDevice->{helper}->{colorValue} != $cv); # color
  2806. }
  2807. elsif (($cl > 0) && ($ledDevice->{helper}->{mode} != 1)) # not color
  2808. {
  2809. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x40".chr($cv)."\x55", $receiver, $delay); # color
  2810. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x4E".chr($cl)."\x55", $receiver, $delay); # brightness
  2811. $ledDevice->{helper}->{mode} = 1; # color
  2812. }
  2813. $ledDevice->{helper}->{colorValue} = $cv;
  2814. $ledDevice->{helper}->{colorLevel} = $cl;
  2815. $ledDevice->{helper}->{whiteLevel} = $wl;
  2816. }
  2817. # unlock ll queue after complete cmd is send
  2818. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x00", $receiver, 0, 1);
  2819. return undef;
  2820. }
  2821. ###############################################################################
  2822. #
  2823. # device specific functions white bulb
  2824. # warm white / cold white with dim, bridge V2|bridge V3
  2825. #
  2826. #
  2827. ###############################################################################
  2828. sub
  2829. WifiLight_White_Pair(@)
  2830. {
  2831. my ($ledDevice, $numSeconds) = @_;
  2832. $numSeconds = 1 if !(defined($numSeconds));
  2833. my @bulbCmdsOn = ("\x38", "\x3D", "\x37", "\x32");
  2834. Log3 ($ledDevice, 3, "$ledDevice->{NAME}, $ledDevice->{LEDTYPE} at $ledDevice->{CONNECTION}, slot $ledDevice->{SLOT}: pair $numSeconds");
  2835. # find my slot and get my group-all-on cmd
  2836. my $ctrl = @bulbCmdsOn[$ledDevice->{SLOT} -1]."\x00\x55";
  2837. for (my $i = 0; $i < $numSeconds; $i++)
  2838. {
  2839. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
  2840. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 500, undef, undef);
  2841. }
  2842. return undef;
  2843. }
  2844. sub
  2845. WifiLight_White_UnPair(@)
  2846. {
  2847. my ($ledDevice, $numSeconds, $releaseFromSlot) = @_;
  2848. $numSeconds = 5;
  2849. my @bulbCmdsOn = ("\x38", "\x3D", "\x37", "\x32");
  2850. Log3 ($ledDevice, 3, "$ledDevice->{NAME}, $ledDevice->{LEDTYPE} at $ledDevice->{CONNECTION}, slot $ledDevice->{SLOT}: unpair $numSeconds");
  2851. # find my slot and get my group-all-on cmd
  2852. my $ctrl = @bulbCmdsOn[$ledDevice->{SLOT} -1]."\x00\x55";
  2853. for (my $i = 0; $i < $numSeconds; $i++)
  2854. {
  2855. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 250, undef, undef);
  2856. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 250, undef, undef);
  2857. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 250, undef, undef);
  2858. WifiLight_HighLevelCmdQueue_Add($ledDevice, undef, undef, undef, $ctrl, 250, undef, undef);
  2859. }
  2860. return undef;
  2861. }
  2862. sub
  2863. WifiLight_White_Sync(@)
  2864. {
  2865. my ($ledDevice) = @_;
  2866. my @bulbCmdsOn = ("\x38", "\x3D", "\x37", "\x32");
  2867. my @bulbCmdsFB = ("\xB8", "\xBD", "\xB7", "\xB2");
  2868. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  2869. my $delay = 100;
  2870. $ledDevice->{helper}->{whiteLevel} =11;
  2871. Log3 ($ledDevice, 3, "$ledDevice->{NAME}, $ledDevice->{LEDTYPE} at $ledDevice->{CONNECTION}, slot $ledDevice->{SLOT}: sync");
  2872. WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOn[$ledDevice->{SLOT} -1]."\x00\x55", $receiver, $delay); # group on
  2873. WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsFB[$ledDevice->{SLOT} -1]."\x00\x55", $receiver, $delay); # full brightness
  2874. WifiLight_setHSV_Readings($ledDevice, 0, 0, 100) if $init_done;
  2875. return undef;
  2876. }
  2877. sub
  2878. WifiLight_White_On(@)
  2879. {
  2880. my ($ledDevice, $ramp) = @_;
  2881. Log3 ($ledDevice, 3, "$ledDevice->{NAME} white slot $ledDevice->{SLOT} set on $ramp");
  2882. return WifiLight_HSV_Transition($ledDevice, 0, 0, 100, $ramp, '', 500, undef);
  2883. }
  2884. sub
  2885. WifiLight_White_Off(@)
  2886. {
  2887. my ($ledDevice, $ramp) = @_;
  2888. Log3 ($ledDevice, 3, "$ledDevice->{NAME} white slot $ledDevice->{SLOT} set off $ramp");
  2889. return WifiLight_RGBW2_Dim($ledDevice, 0, $ramp, '');
  2890. }
  2891. sub
  2892. WifiLight_White_Dim(@)
  2893. {
  2894. my ($ledDevice, $level, $ramp, $flags) = @_;
  2895. my $h = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  2896. my $s = ReadingsVal($ledDevice->{NAME}, "saturation", 0);
  2897. Log3 ($ledDevice, 3, "$ledDevice->{NAME} white slot $ledDevice->{SLOT} dim $level $ramp $flags");
  2898. return WifiLight_HSV_Transition($ledDevice, $h, $s, $level, $ramp, $flags, 300, undef);
  2899. }
  2900. # only val supported,
  2901. # TODO hue will become colortemp
  2902. sub
  2903. WifiLight_White_setHSV(@)
  2904. {
  2905. my ($ledDevice, $hue, $sat, $val) = @_;
  2906. my $wlStep = (100 / 11);
  2907. WifiLight_setHSV_Readings($ledDevice, 0, 0, $val);
  2908. $val = int(($val / $wlStep) +0.5);
  2909. WifiLight_White_setLevels($ledDevice, undef, $val);
  2910. return undef;
  2911. }
  2912. sub
  2913. WifiLight_White_setLevels(@)
  2914. {
  2915. my ($ledDevice, $cv, $wl) = @_;
  2916. my @bulbCmdsOn = ("\x38", "\x3D", "\x37", "\x32");
  2917. my @bulbCmdsOff = ("\x3B", "\x33", "\x3A", "\x36");
  2918. my @bulbCmdsFull = ("\xB8", "\xBD", "\xB7", "\xB2");
  2919. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  2920. my $delay = 80;
  2921. # alert that dump receiver, give it a extra wake up call
  2922. if ($ledDevice->{helper}->{whiteLevel} != $wl)
  2923. {
  2924. WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOn[$ledDevice->{SLOT} -1]."\x00\x55", $receiver, $delay);
  2925. WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOn[$ledDevice->{SLOT} -1]."\x00\x55", $receiver, $delay);
  2926. }
  2927. if ($ledDevice->{helper}->{whiteLevel} > $wl)
  2928. {
  2929. WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOn[$ledDevice->{SLOT} -1]."\x00\x55", $receiver, $delay); # group on
  2930. for (my $i=$ledDevice->{helper}->{whiteLevel}; $i > $wl; $i--)
  2931. {
  2932. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x34\x00\x55", $receiver, $delay); # brightness down
  2933. $ledDevice->{helper}->{whiteLevel} = $i - 1;
  2934. }
  2935. if ($wl == 0)
  2936. {
  2937. # special precaution, giving extra downsteps to do a sync each time you switch off
  2938. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x34\x00\x55", $receiver, $delay); # brightness down
  2939. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x34\x00\x55", $receiver, $delay); # brightness down
  2940. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x34\x00\x55", $receiver, $delay); # brightness down
  2941. WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOff[$ledDevice->{SLOT} -1]."\x00\x55", $receiver, $delay); # group off
  2942. #WifiLight_LowLevelCmdqueue_Add($ledDevice, @bulbCmdsOff[$ledDevice->{SLOT}-1]."\x00\x55", $receiver, $delay);
  2943. }
  2944. }
  2945. if ($ledDevice->{helper}->{whiteLevel} < $wl)
  2946. {
  2947. $ledDevice->{helper}->{whiteLevel} = 1 if ($ledDevice->{helper}->{whiteLevel} == 0);
  2948. WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsOn[$ledDevice->{SLOT} -1]."\x00\x55", $receiver, $delay); # group on
  2949. for (my $i=$ledDevice->{helper}->{whiteLevel}; $i < $wl; $i++)
  2950. {
  2951. WifiLight_LowLevelCmdQueue_Add($ledDevice, "\x3C\x00\x55", $receiver, $delay); # brightness up
  2952. $ledDevice->{helper}->{whiteLevel} = $i + 1;
  2953. }
  2954. WifiLight_LowLevelCmdQueue_Add($ledDevice, @bulbCmdsFull[$ledDevice->{SLOT} -1]."\x00\x55", $receiver, $delay) if ($ledDevice->{helper}->{whiteLevel} == 11);
  2955. }
  2956. return undef;
  2957. }
  2958. ###############################################################################
  2959. #
  2960. # device indepenent routines
  2961. #
  2962. ###############################################################################
  2963. # dispatcher
  2964. sub
  2965. WifiLight_setHSV(@)
  2966. {
  2967. my ($ledDevice, $hue, $sat, $val, $isLast) = @_;
  2968. return WifiLight_RGBWLD316_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316'));
  2969. return WifiLight_RGBWLD316A_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD316A'));
  2970. return WifiLight_RGBWLD382_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382'));
  2971. return WifiLight_RGBLD382_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382'));
  2972. return WifiLight_RGBWLD382A_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'LD382A'));
  2973. return WifiLight_RGBLD382A_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'LD382A'));
  2974. return WifiLight_RGBLW12_setHSV($ledDevice, $hue, $sat, $val) if ($ledDevice->{CONNECTION} eq 'LW12');
  2975. return WifiLight_RGBLW12HX_setHSV($ledDevice, $hue, $sat, $val) if ($ledDevice->{CONNECTION} eq 'LW12HX');
  2976. return WifiLight_RGBLW12FC_setHSV($ledDevice, $hue, $sat, $val) if ($ledDevice->{CONNECTION} eq 'LW12FC');
  2977. return WifiLight_WhiteSENGLED_setHSV($ledDevice, $hue, $sat, $val, $isLast) if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} eq 'SENGLED'));
  2978. return WifiLight_RGB_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  2979. return WifiLight_RGBW1_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq "RGBW1") && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  2980. return WifiLight_RGBW2_setHSV($ledDevice, $hue, $sat, $val, $isLast) if ($ledDevice->{LEDTYPE} eq "RGBW2");
  2981. return WifiLight_White_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'White') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'));
  2982. return WifiLight_DualWhiteSunricher_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'DualWhite') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
  2983. return WifiLight_RGBSunricher_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
  2984. return WifiLight_RGBSunricherA_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} eq 'SUNRICHERA'));
  2985. return WifiLight_RGBWSunricher_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'SUNRICHER'));
  2986. return WifiLight_RGBWSunricherA_setHSV($ledDevice, $hue, $sat, $val) if (($ledDevice->{LEDTYPE} eq 'RGBW') && ($ledDevice->{CONNECTION} eq 'SUNRICHERA'));
  2987. return undef;
  2988. }
  2989. # dispatcher
  2990. sub
  2991. WifiLight_processEvent(@)
  2992. {
  2993. my ($ledDevice, $event, $progress) = @_;
  2994. Log3 ($ledDevice, 4, "$ledDevice->{NAME} processEvent: $event, progress: $progress") if defined($event);
  2995. DoTrigger($ledDevice->{NAME}, "programm: $event $progress",0) if defined($event);
  2996. return undef;
  2997. }
  2998. sub
  2999. WifiLight_HSV_Transition(@)
  3000. {
  3001. my ($ledDevice, $hue, $sat, $val, $ramp, $flags, $delay, $event) = @_;
  3002. my ($hueFrom, $satFrom, $valFrom, $timeFrom);
  3003. # minimum stepwide
  3004. my $defaultDelay = $delay;
  3005. # if queue in progess set start vals to last cached hsv target, else set start to actual hsv
  3006. if (@{$ledDevice->{helper}->{hlCmdQueue}} > 0)
  3007. {
  3008. $hueFrom = $ledDevice->{helper}->{targetHue};
  3009. $satFrom = $ledDevice->{helper}->{targetSat};
  3010. $valFrom = $ledDevice->{helper}->{targetVal};
  3011. $timeFrom = $ledDevice->{helper}->{targetTime};
  3012. Log3 ($ledDevice, 5, "$ledDevice->{NAME} prepare start hsv transition (is cached) hsv $hueFrom, $satFrom, $valFrom, $timeFrom");
  3013. }
  3014. else
  3015. {
  3016. $hueFrom = $ledDevice->{READINGS}->{hue}->{VAL} || 0;
  3017. $satFrom = $ledDevice->{READINGS}->{saturation}->{VAL} || 0;
  3018. $valFrom = $ledDevice->{READINGS}->{brightness}->{VAL} || 0;
  3019. $timeFrom = gettimeofday();
  3020. Log3 ($ledDevice, 5, "$ledDevice->{NAME} prepare start hsv transition (is actual) hsv $hueFrom, $satFrom, $valFrom, $timeFrom");
  3021. }
  3022. Log3 ($ledDevice, 4, "$ledDevice->{NAME} current HSV $hueFrom, $satFrom, $valFrom");
  3023. Log3 ($ledDevice, 3, "$ledDevice->{NAME} set HSV $hue, $sat, $val with ramp: $ramp, flags: ". $flags);
  3024. # if there is no ramp we dont need transition
  3025. if (($ramp || 0) == 0)
  3026. {
  3027. Log3 ($ledDevice, 4, "$ledDevice->{NAME} hsv transition without ramp routed to direct settings, hsv $hue, $sat, $val");
  3028. $ledDevice->{helper}->{targetTime} = $timeFrom;
  3029. return WifiLight_HighLevelCmdQueue_Add($ledDevice, $hue, $sat, $val, undef, $delay, 100, $event, $timeFrom);
  3030. }
  3031. # calculate the left and right turn length based
  3032. # startAngle +360 -endAngle % 360 = counter clock
  3033. # endAngle +360 -startAngle % 360 = clockwise
  3034. my $fadeLeft = ($hueFrom + 360 - $hue) % 360;
  3035. my $fadeRight = ($hue + 360 - $hueFrom) % 360;
  3036. my $direction = ($fadeLeft <=> $fadeRight); # -1 = counterclock, +1 = clockwise
  3037. $direction = ($direction == 0)?1:$direction; # in dupt cw
  3038. Log3 ($ledDevice, 4, "$ledDevice->{NAME} color rotation dev cc:$fadeLeft, cw:$fadeRight, shortest:$direction");
  3039. $direction *= -1 if ($flags =~ m/.*[lL].*/); # reverse if long path desired (flag l or L is set)
  3040. my $rotation = ($direction == 1)?$fadeRight:$fadeLeft; # angle of hue rotation in based on flags
  3041. my $sFade = abs($sat - $satFrom);
  3042. my $vFade = abs($val - $valFrom);
  3043. my ($stepWide, $steps, $hueToSet, $hueStep, $satToSet, $satStep, $valToSet, $valStep);
  3044. # fix if there is in fact no transition, blocks queue for given ramp time with actual hsv values
  3045. if ($rotation == 0 && $sFade == 0 && $vFade == 0)
  3046. {
  3047. Log3 ($ledDevice, 4, "$ledDevice->{NAME} hsv transition with unchaned settings, hsv $hue, $sat, $val, ramp $ramp");
  3048. #TODO remove if tested
  3049. #WifiLight_HighLevelCmdQueue_Add($ledDevice, $hue, $sat, $val, undef, $ramp * 1000, 0, $event, $timeFrom);
  3050. $ledDevice->{helper}->{targetTime} = $timeFrom + $ramp;
  3051. return WifiLight_HighLevelCmdQueue_Add($ledDevice, $hue, $sat, $val, undef, $delay, 100, $event, $timeFrom + $ramp);
  3052. }
  3053. if (($rotation >= $sFade) && ($rotation >= $vFade))
  3054. {
  3055. $stepWide = ($ramp * 1000 / $rotation); # how long is one step (set hsv) in ms based on hue
  3056. $stepWide = $defaultDelay if ($stepWide < $defaultDelay);
  3057. $steps = int($ramp * 1000 / $stepWide); # how many steps will we need ?
  3058. Log3 ($ledDevice, 4, "$ledDevice->{NAME} transit (H>S||V) steps: $steps stepwide: $stepWide");
  3059. }
  3060. elsif (($sFade >= $rotation) && ($sFade >= $vFade))
  3061. {
  3062. $stepWide = ($ramp * 1000 / $sFade); # how long is one step (set hsv) in ms based on sat
  3063. $stepWide = $defaultDelay if ($stepWide < $defaultDelay);
  3064. $steps = int($ramp * 1000 / $stepWide); # how many steps will we need ?
  3065. Log3 ($ledDevice, 4, "$ledDevice->{NAME} transit (S>H||V) steps: $steps stepwide: $stepWide");
  3066. }
  3067. else
  3068. {
  3069. $stepWide = ($ramp * 1000 / $vFade); # how long is one step (set hsv) in ms based on val
  3070. $stepWide = $defaultDelay if ($stepWide < $defaultDelay);
  3071. $steps = int($ramp * 1000 / $stepWide); # how many steps will we need ?
  3072. Log3 ($ledDevice, 4, "$ledDevice->{NAME} transit (V>H||S) steps: $steps stepwide: $stepWide");
  3073. }
  3074. $hueToSet = $hueFrom; # prepare tmp working hue
  3075. $hueStep = $rotation / $steps * $direction; # how big is one hue step base on timing choosen
  3076. $satToSet = $satFrom; # prepare workin sat
  3077. $satStep = ($sat - $satFrom) / $steps;
  3078. $valToSet = $valFrom;
  3079. $valStep = ($val - $valFrom) / $steps;
  3080. #TODO do something more flexible
  3081. #TODO remove if tested
  3082. # $timeFrom += 1;
  3083. for (my $i=1; $i <= $steps; $i++)
  3084. {
  3085. $hueToSet += $hueStep;
  3086. $hueToSet -= 360 if ($hueToSet > 360); #handle turn over zero
  3087. $hueToSet += 360 if ($hueToSet < 0);
  3088. $satToSet += $satStep;
  3089. $valToSet += $valStep;
  3090. my $progress = 100 / $steps * $i;
  3091. Log3 ($ledDevice, 4, "$ledDevice->{NAME} add to hl queue h:".($hueToSet).", s:".($satToSet).", v:".($valToSet)." ($i/$steps)");
  3092. WifiLight_HighLevelCmdQueue_Add($ledDevice, int($hueToSet +0.5), int($satToSet +0.5), int($valToSet +0.5), undef, $stepWide, int($progress +0.5), $event, $timeFrom + (($i-1) * $stepWide / 1000) );
  3093. }
  3094. $ledDevice->{helper}->{targetTime} = $timeFrom + $ramp;
  3095. return undef;
  3096. }
  3097. sub
  3098. WifiLight_SetHSV_Target(@)
  3099. {
  3100. my ($ledDevice, $hue, $sat, $val) = @_;
  3101. $ledDevice->{helper}->{targetHue} = $hue;
  3102. $ledDevice->{helper}->{targetSat} = $sat;
  3103. $ledDevice->{helper}->{targetVal} = $val;
  3104. return undef;
  3105. }
  3106. sub
  3107. WifiLight_setHSV_Readings(@)
  3108. {
  3109. my ($ledDevice, $hue, $sat, $val) = @_;
  3110. my ($r, $g, $b) = WifiLight_HSV2RGB($hue, $sat, $val);
  3111. readingsBeginUpdate($ledDevice);
  3112. readingsBulkUpdate($ledDevice, "hue", $hue % 360);
  3113. readingsBulkUpdate($ledDevice, "saturation", $sat);
  3114. readingsBulkUpdate($ledDevice, "brightness", $val);
  3115. readingsBulkUpdate($ledDevice, "RGB", sprintf("%02X%02X%02X",$r,$g,$b));
  3116. readingsBulkUpdate($ledDevice, "state", "on") if ($val > 0);
  3117. readingsBulkUpdate($ledDevice, "state", "off") if ($val == 0);
  3118. readingsEndUpdate($ledDevice, 1);
  3119. }
  3120. sub
  3121. WifiLight_HSV2RGB(@)
  3122. {
  3123. my ($hue, $sat, $val) = @_;
  3124. if ($sat == 0)
  3125. {
  3126. return int(($val * 2.55) +0.5), int(($val * 2.55) +0.5), int(($val * 2.55) +0.5);
  3127. }
  3128. $hue %= 360;
  3129. $hue /= 60;
  3130. $sat /= 100;
  3131. $val /= 100;
  3132. my $i = int($hue);
  3133. my $f = $hue - $i;
  3134. my $p = $val * (1 - $sat);
  3135. my $q = $val * (1 - $sat * $f);
  3136. my $t = $val * (1 - $sat * (1 - $f));
  3137. my ($r, $g, $b);
  3138. if ( $i == 0 )
  3139. {
  3140. ($r, $g, $b) = ($val, $t, $p);
  3141. }
  3142. elsif ( $i == 1 )
  3143. {
  3144. ($r, $g, $b) = ($q, $val, $p);
  3145. }
  3146. elsif ( $i == 2 )
  3147. {
  3148. ($r, $g, $b) = ($p, $val, $t);
  3149. }
  3150. elsif ( $i == 3 )
  3151. {
  3152. ($r, $g, $b) = ($p, $q, $val);
  3153. }
  3154. elsif ( $i == 4 )
  3155. {
  3156. ($r, $g, $b) = ($t, $p, $val);
  3157. }
  3158. else
  3159. {
  3160. ($r, $g, $b) = ($val, $p, $q);
  3161. }
  3162. return (int(($r * 255) +0.5), int(($g * 255) +0.5), int(($b * 255) + 0.5));
  3163. }
  3164. sub
  3165. WifiLight_RGB2HSV(@)
  3166. {
  3167. my ($ledDevice, $in) = @_;
  3168. my $r = hex substr($in, 0, 2);
  3169. my $g = hex substr($in, 2, 2);
  3170. my $b = hex substr($in, 4, 2);
  3171. my ($max, $min, $delta);
  3172. my ($h, $s, $v);
  3173. $max = $r if (($r >= $g) && ($r >= $b));
  3174. $max = $g if (($g >= $r) && ($g >= $b));
  3175. $max = $b if (($b >= $r) && ($b >= $g));
  3176. $min = $r if (($r <= $g) && ($r <= $b));
  3177. $min = $g if (($g <= $r) && ($g <= $b));
  3178. $min = $b if (($b <= $r) && ($b <= $g));
  3179. $v = int(($max / 2.55) + 0.5);
  3180. $delta = $max - $min;
  3181. my $currentHue = ReadingsVal($ledDevice->{NAME}, "hue", 0);
  3182. return ($currentHue, 0, $v) if (($max == 0) || ($delta == 0));
  3183. $s = int((($delta / $max) *100) + 0.5);
  3184. $h = ($g - $b) / $delta if ($r == $max);
  3185. $h = 2 + ($b - $r) / $delta if ($g == $max);
  3186. $h = 4 + ($r - $g) / $delta if ($b == $max);
  3187. $h = int(($h * 60) + 0.5);
  3188. $h += 360 if ($h < 0);
  3189. return $h, $s, $v;
  3190. }
  3191. sub
  3192. WifiLight_HSV2fourChannel(@)
  3193. {
  3194. my ($h, $s, $v) = @_;
  3195. my ($r, $g, $b) = WifiLight_HSV2RGB($h, $s, $v);
  3196. #white part, base 255
  3197. my $white = 255;
  3198. foreach ($r, $g, $b) { $white = $_ if ($_ < $white); }
  3199. #remaining color part
  3200. my ($rr, $rg, $rb);
  3201. $rr = $r - $white;
  3202. $rg = $g - $white;
  3203. $rb = $b - $white;
  3204. return ($rr, $rg, $rb, $white);
  3205. }
  3206. sub
  3207. WifiLight_Milight_ColorConverter(@)
  3208. {
  3209. my ($ledDevice, $cr, $cy, $cg, $cc, $cb, $cm) = @_;
  3210. #my ($ledDevice) = @_;
  3211. my @colorMap;
  3212. #my $hueRed = 0;
  3213. my $adjRed = 0 - ($cr || 0);
  3214. #my $hueYellow = 60;
  3215. my $adjYellow = 60 - ($cy || 0);
  3216. #my $hueGreen = 120;
  3217. my $adjGreen = 120 - ($cg || 0);
  3218. #my $hueCyan = 180;
  3219. my $adjCyan = 180 - ($cc || 0);
  3220. #my $hueBlue = 240;
  3221. my $adjBlue = 240 - ($cb || 0);
  3222. #my $hueLilac = 300;
  3223. my $adjLilac = 300 - ($cm || 0);
  3224. #st34
  3225. my $devRed = 168;
  3226. #my $devRed = 176;
  3227. my $devYellow = 134;
  3228. #my $devYellow = 144;
  3229. my $devGreen = 88;
  3230. #my $devCyan = 48;
  3231. my $devCyan = 56;
  3232. my $devBlue = 8;
  3233. my $devLilac = 208; #224
  3234. my $i= 360;
  3235. # red to yellow
  3236. $adjRed += 360 if ($adjRed < 0); # in case of negative adjustment
  3237. $devRed += 256 if ($devRed < $devYellow);
  3238. $adjYellow += 360 if ($adjYellow < $adjRed);
  3239. for ($i = $adjRed; $i <= $adjYellow; $i++)
  3240. {
  3241. $colorMap[$i % 360] = ($devRed - int((($devRed - $devYellow) / ($adjYellow - $adjRed) * ($i - $adjRed)) +0.5)) % 255;
  3242. Log3 ($ledDevice, 4, "$ledDevice->{NAME} create colormap h: ".($i % 360)." d: ".$colorMap[$i % 360]);
  3243. }
  3244. #yellow to green
  3245. $devYellow += 256 if ($devYellow < $devGreen);
  3246. $adjGreen += 360 if ($adjGreen < $adjYellow);
  3247. for ($i = $adjYellow; $i <= $adjGreen; $i++)
  3248. {
  3249. $colorMap[$i % 360] = ($devYellow - int((($devYellow - $devGreen) / ($adjGreen - $adjYellow) * ($i - $adjYellow)) +0.5)) % 255;
  3250. Log3 ($ledDevice, 4, "$ledDevice->{NAME} create colormap h: ".($i % 360)." d: ".$colorMap[$i % 360]);
  3251. }
  3252. #green to cyan
  3253. $devGreen += 256 if ($devGreen < $devCyan);
  3254. $adjCyan += 360 if ($adjCyan < $adjGreen);
  3255. for ($i = $adjGreen; $i <= $adjCyan; $i++)
  3256. {
  3257. $colorMap[$i % 360] = ($devGreen - int((($devGreen - $devCyan) / ($adjCyan - $adjGreen) * ($i - $adjGreen)) +0.5)) % 255;
  3258. Log3 ($ledDevice, 4, "$ledDevice->{NAME} create colormap h: ".($i % 360)." d: ".$colorMap[$i % 360]);
  3259. }
  3260. #cyan to blue
  3261. $devCyan += 256 if ($devCyan < $devCyan);
  3262. $adjBlue += 360 if ($adjBlue < $adjCyan);
  3263. for ($i = $adjCyan; $i <= $adjBlue; $i++)
  3264. {
  3265. $colorMap[$i % 360] = ($devCyan - int((($devCyan - $devBlue) / ($adjBlue - $adjCyan) * ($i - $adjCyan)) +0.5)) % 255;
  3266. Log3 ($ledDevice, 4, "$ledDevice->{NAME} create colormap h: ".($i % 360)." d: ".$colorMap[$i % 360]);
  3267. }
  3268. #blue to lilac
  3269. $devBlue += 256 if ($devBlue < $devLilac);
  3270. $adjLilac += 360 if ($adjLilac < $adjBlue);
  3271. for ($i = $adjBlue; $i <= $adjLilac; $i++)
  3272. {
  3273. $colorMap[$i % 360] = ($devBlue - int((($devBlue - $devLilac) / ($adjLilac - $adjBlue) * ($i- $adjBlue)) +0.5)) % 255;
  3274. Log3 ($ledDevice, 4, "$ledDevice->{NAME} create colormap h: ".($i % 360)." d: ".$colorMap[$i % 360]);
  3275. }
  3276. #lilac to red
  3277. $devLilac += 256 if ($devLilac < $devRed);
  3278. $adjRed += 360 if ($adjRed < $adjLilac);
  3279. for ($i = $adjLilac; $i <= $adjRed; $i++)
  3280. {
  3281. $colorMap[$i % 360] = ($devLilac - int((($devLilac - $devRed) / ($adjRed - $adjLilac) * ($i - $adjLilac)) +0.5)) % 255;
  3282. Log3 ($ledDevice, 4, "$ledDevice->{NAME} create colormap h: ".($i % 360)." d: ".$colorMap[$i % 360]);
  3283. }
  3284. @{$ledDevice->{helper}->{COLORMAP}} = @colorMap;
  3285. return \@colorMap;
  3286. }
  3287. sub
  3288. WifiLight_RGB_ColorConverter(@)
  3289. {
  3290. # default correction +/- 29°
  3291. my ($ledDevice, $cr, $cy, $cg, $cc, $cb, $cm) = @_;
  3292. #my ($cr, $cy, $cg, $cc, $cb, $cm) = (0, -30, -10, -30, 0, -10);
  3293. my @colorMap;
  3294. for (my $i = 0; $i <= 360; $i++)
  3295. {
  3296. my $toR = WifiLight_HueDistance(0, $i);
  3297. my $toY = WifiLight_HueDistance(60, $i);
  3298. my $toG = WifiLight_HueDistance(120, $i);
  3299. my $toC = WifiLight_HueDistance(180, $i);
  3300. my $toB = WifiLight_HueDistance(240, $i);
  3301. my $toM = WifiLight_HueDistance(300, $i);
  3302. my $c = 0; # $i;
  3303. $c += $cr - ($cr * $toR / 60) if (abs($toR) <= 60);
  3304. $c += $cy - ($cy * $toY / 60) if (abs($toY) <= 60);
  3305. $c += $cg - ($cg * $toG / 60) if (abs($toG) <= 60);
  3306. $c += $cc - ($cc * $toC / 60) if (abs($toC) <= 60);
  3307. $c += $cb - ($cb * $toB / 60) if (abs($toB) <= 60);
  3308. $c += $cm - ($cm * $toM / 60) if (abs($toM) <= 60);
  3309. $colorMap[$i] = int($i + $c + 0.5) % 360;
  3310. #$colorMap[$i] = (int($colorMap[$i] + ($cr - ($cr * $toR / 45)) + 0.5) + 360) % 360 if (abs($toR) <= 45);
  3311. #$colorMap[$i] = (int($colorMap[$i] + ($cy - ($cy * $toY / 45)) + 0.5) + 360) % 360 if (abs($toY) <= 45);
  3312. #$colorMap[$i] = (int($colorMap[$i] + ($cg - ($cg * $toG / 45)) + 0.5) + 360) % 360 if (abs($toG) <= 45);
  3313. }
  3314. @{$ledDevice->{helper}->{COLORMAP}} = @colorMap;
  3315. return \@colorMap;
  3316. }
  3317. # calculate the distance of two given hue
  3318. sub
  3319. WifiLight_HueDistance(@)
  3320. {
  3321. my ($hue, $testHue) = @_;
  3322. my $a = (360 + $hue - $testHue) % 360;
  3323. my $b = (360 + $testHue - $hue) % 360;
  3324. return ($a, $b)[$a > $b];
  3325. }
  3326. # helper for easying access to attrib
  3327. sub
  3328. WifiLight_ccAttribVal(@)
  3329. {
  3330. my ($ledDevice, $dr, $dy, $dg, $dc, $db, $dm) = @_;
  3331. my $a = AttrVal($ledDevice->{NAME}, 'colorCast', undef);
  3332. if ($a)
  3333. {
  3334. my ($cr, $cy, $cg, $cc, $cb, $cm) = split (',', $a);
  3335. }
  3336. else
  3337. {
  3338. my ($cr, $cy, $cg, $cc, $cb, $cm) = ($dr, $dy, $dg, $dc, $db, $dm);
  3339. }
  3340. return ($dr, $dy, $dg, $dc, $db, $dm);
  3341. }
  3342. sub
  3343. WifiLight_CreateGammaMapping(@)
  3344. {
  3345. my ($ledDevice, $gamma) = @_;
  3346. my @gammaMap;
  3347. for (my $i = 0; $i <= 100; $i += 1)
  3348. {
  3349. my $correction = ($i / 100) ** (1 / $gamma);
  3350. $gammaMap[$i] = $correction * 100;
  3351. Log3 ($ledDevice, 5, "$ledDevice->{NAME} create gammamap v-in: ".$i.", v-out: $gammaMap[$i]");
  3352. }
  3353. return \@gammaMap;
  3354. }
  3355. ###############################################################################
  3356. #
  3357. # high level queue, long running color transitions
  3358. #
  3359. ###############################################################################
  3360. sub
  3361. WifiLight_HighLevelCmdQueue_Add(@)
  3362. {
  3363. my ($ledDevice, $hue, $sat, $val, $ctrl, $delay, $progress, $event, $targetTime) = @_;
  3364. my $cmd;
  3365. $cmd->{hue} = $hue;
  3366. $cmd->{sat} = $sat;
  3367. $cmd->{val} = $val;
  3368. # $cmd->{k} = $k;
  3369. $cmd->{ctrl} = $ctrl;
  3370. $cmd->{delay} = $delay;
  3371. $cmd->{progress} = $progress;
  3372. $cmd->{event} = $event;
  3373. $cmd->{targetTime} = $targetTime;
  3374. $cmd->{inProgess} = 0;
  3375. push @{$ledDevice->{helper}->{hlCmdQueue}}, $cmd;
  3376. my $dbgStr = unpack("H*", $cmd->{ctrl} || '');
  3377. Log3 ($ledDevice, 4, "$ledDevice->{NAME} high level cmd queue add hsv/ctrl $cmd->{hue}, $cmd->{sat}, $cmd->{val}, ctrl $dbgStr, targetTime $cmd->{targetTime}, qlen ".@{$ledDevice->{helper}->{hlCmdQueue}});
  3378. my $actualCmd = @{$ledDevice->{helper}->{hlCmdQueue}}[0];
  3379. # sender busy ?
  3380. return undef if (($actualCmd->{inProgess} || 0) == 1);
  3381. return WifiLight_HighLevelCmdQueue_Exec($ledDevice);
  3382. }
  3383. sub
  3384. WifiLight_HighLevelCmdQueue_Exec(@)
  3385. {
  3386. my ($ledDevice) = @_;
  3387. my $actualCmd = @{$ledDevice->{helper}->{hlCmdQueue}}[0];
  3388. # transmission complete, remove
  3389. shift @{$ledDevice->{helper}->{hlCmdQueue}} if ($actualCmd->{inProgess});
  3390. # next in queue
  3391. $actualCmd = @{$ledDevice->{helper}->{hlCmdQueue}}[0];
  3392. my $nextCmd = @{$ledDevice->{helper}->{hlCmdQueue}}[1];
  3393. # return if no more elements in queue
  3394. return undef if (!defined($actualCmd->{inProgess}));
  3395. # drop frames if next frame is already sceduled for given time. do not drop if it is the last frame or if it is a command
  3396. while (defined($nextCmd->{targetTime}) && ($nextCmd->{targetTime} < gettimeofday()) && !$actualCmd->{ctrl})
  3397. {
  3398. shift @{$ledDevice->{helper}->{hlCmdQueue}};
  3399. $actualCmd = @{$ledDevice->{helper}->{hlCmdQueue}}[0];
  3400. $nextCmd = @{$ledDevice->{helper}->{hlCmdQueue}}[1];
  3401. Log3 ($ledDevice, 4, "$ledDevice->{NAME} high level cmd queue exec drop frame at hlQueue level. hl qlen: ".@{$ledDevice->{helper}->{hlCmdQueue}});
  3402. }
  3403. Log3 ($ledDevice, 5, "$ledDevice->{NAME} high level cmd queue exec dropper delay: ".($actualCmd->{targetTime} - gettimeofday()) );
  3404. # set hsv or if a device ctrl command is sceduled: send it and ignore hsv
  3405. if ($actualCmd->{ctrl})
  3406. {
  3407. my $dbgStr = unpack("H*", $actualCmd->{ctrl});
  3408. Log3 ($ledDevice, 4, "$ledDevice->{NAME} high level cmd queue exec ctrl $dbgStr, qlen ".@{$ledDevice->{helper}->{hlCmdQueue}});
  3409. WifiLight_sendCtrl($ledDevice, $actualCmd->{ctrl});
  3410. }
  3411. else
  3412. {
  3413. my $isLast = (@{$ledDevice->{helper}->{hlCmdQueue}} == 1)?1:undef;
  3414. if (($ledDevice->{helper}->{llLock} == 0) || $isLast)
  3415. {
  3416. Log3 ($ledDevice, 4, "$ledDevice->{NAME} high level cmd queue exec hsv $actualCmd->{hue}, $actualCmd->{sat}, $actualCmd->{val}, delay $actualCmd->{delay}, hl qlen ".@{$ledDevice->{helper}->{hlCmdQueue}}.", ll qlen ".@{$ledDevice->{helper}->{llCmdQueue}}.", lock ".$ledDevice->{helper}->{llLock});
  3417. WifiLight_setHSV($ledDevice, $actualCmd->{hue}, $actualCmd->{sat}, $actualCmd->{val}, $isLast);
  3418. }
  3419. else
  3420. {
  3421. Log3 ($ledDevice, 5, "$ledDevice->{NAME} high level cmd queue exec drop frame at llQueue level. ll qlen: ".@{$ledDevice->{helper}->{llCmdQueue}}.", lock ".$ledDevice->{helper}->{llLock});
  3422. }
  3423. }
  3424. $actualCmd->{inProgess} = 1;
  3425. my $next = defined($nextCmd->{targetTime})?$nextCmd->{targetTime}:gettimeofday() + ($actualCmd->{delay} / 1000);
  3426. Log3 ($ledDevice, 4, "$ledDevice->{NAME} high level cmd queue ask next $next");
  3427. InternalTimer($next, "WifiLight_HighLevelCmdQueue_Exec", $ledDevice, 0);
  3428. WifiLight_processEvent($ledDevice, $actualCmd->{event}, $actualCmd->{progress});
  3429. return undef;
  3430. }
  3431. sub
  3432. WifiLight_HighLevelCmdQueue_Clear(@)
  3433. {
  3434. my ($ledDevice) = @_;
  3435. Log3 ($ledDevice, 4, "$ledDevice->{NAME} high level cmd queue clear");
  3436. RemoveInternalTimer($ledDevice, 'WifiLight_HighLevelCmdQueue_Exec');
  3437. $ledDevice->{helper}->{hlCmdQueue} = [];
  3438. }
  3439. # dispatcher for ctrl cmd
  3440. sub
  3441. WifiLight_sendCtrl(@)
  3442. {
  3443. my ($ledDevice, $ctrl) = @_;
  3444. # TODO adjust for all bridge types
  3445. if (($ledDevice->{LEDTYPE} eq 'RGB') && ($ledDevice->{CONNECTION} =~ 'bridge-V[2|3]'))
  3446. {
  3447. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  3448. my $delay = 100;
  3449. WifiLight_LowLevelCmdQueue_Add($ledDevice, $ctrl, $receiver, $delay);
  3450. }
  3451. if ($ledDevice->{LEDTYPE} eq 'RGBW1')
  3452. {
  3453. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  3454. my $delay = 100;
  3455. WifiLight_LowLevelCmdQueue_Add($ledDevice, $ctrl, $receiver, $delay);
  3456. }
  3457. if ($ledDevice->{LEDTYPE} eq 'RGBW2')
  3458. {
  3459. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  3460. my $delay = 100;
  3461. WifiLight_LowLevelCmdQueue_Add($ledDevice, $ctrl, $receiver, $delay);
  3462. }
  3463. if ($ledDevice->{LEDTYPE} eq 'White')
  3464. {
  3465. my $receiver = sockaddr_in($ledDevice->{PORT}, inet_aton($ledDevice->{IP}));
  3466. my $delay = 10;
  3467. WifiLight_LowLevelCmdQueue_Add($ledDevice, $ctrl, $receiver, $delay);
  3468. }
  3469. }
  3470. ###############################################################################
  3471. #
  3472. # atomic low level udp communication to device
  3473. # required because there are timing requirements, mostly limitaions in processing speed of the bridge
  3474. # the commands should never be interrupted or canceled because some fhem readings are set in advance
  3475. #
  3476. ###############################################################################
  3477. sub
  3478. WifiLight_LowLevelCmdQueue_Add(@)
  3479. {
  3480. my ($ledDevice, $command, $receiver, $delay, $unlock) = @_;
  3481. my $cmd;
  3482. $cmd->{command} = $command;
  3483. $cmd->{sender} = $ledDevice;
  3484. $cmd->{receiver} = $receiver;
  3485. $cmd->{delay} = $delay;
  3486. $cmd->{unlock} = $unlock;
  3487. $cmd->{inProgess} = 0;
  3488. # push cmd into queue
  3489. push @{$ledDevice->{helper}->{llCmdQueue}}, $cmd;
  3490. my $dbgStr = unpack("H*", $cmd->{command});
  3491. Log3 ($ledDevice, 5, "$ledDevice->{NAME} low level cmd queue add $dbgStr, qlen ".@{$ledDevice->{helper}->{llCmdQueue}});
  3492. my $actualCmd = @{$ledDevice->{helper}->{llCmdQueue}}[0];
  3493. # sender busy ?
  3494. return undef if ($actualCmd->{inProgess});
  3495. return WifiLight_LowLevelCmdQueue_Send($ledDevice);
  3496. }
  3497. sub
  3498. WifiLight_LowLevelCmdQueue_Send(@)
  3499. {
  3500. my ($ledDevice) = @_;
  3501. my $actualCmd = @{$ledDevice->{helper}->{llCmdQueue}}[0];
  3502. # transmission complete, remove
  3503. shift @{$ledDevice->{helper}->{llCmdQueue}} if ($actualCmd->{inProgess});
  3504. # next in queue
  3505. $actualCmd = @{$ledDevice->{helper}->{llCmdQueue}}[0];
  3506. # remove a low level queue lock if present and get next
  3507. while (($actualCmd->{unlock} || 0) == 1)
  3508. {
  3509. $actualCmd->{sender}->{helper}->{llLock} -= 1;
  3510. Log3 ($ledDevice, 5, "$ledDevice->{NAME} | $actualCmd->{sender}->{NAME} unlock queue ".$actualCmd->{sender}->{helper}->{llLock});
  3511. shift @{$ledDevice->{helper}->{llCmdQueue}};
  3512. $actualCmd = @{$ledDevice->{helper}->{llCmdQueue}}[0];
  3513. }
  3514. # return if no more elements in queue
  3515. return undef if (!defined($actualCmd->{command}));
  3516. my $dbgStr = unpack("H*", $actualCmd->{command});
  3517. Log3 ($ledDevice, 5, "$ledDevice->{NAME} low level cmd queue qlen ".@{$ledDevice->{helper}->{llCmdQueue}}.", send $dbgStr");
  3518. # TCP
  3519. if ($ledDevice->{PROTO})
  3520. {
  3521. if (!$ledDevice->{helper}->{SOCKET} || ($ledDevice->{helper}->{SELECT}->can_read(0) && !$ledDevice->{helper}->{SOCKET}->recv(my $data, 512)))
  3522. {
  3523. Log3 ($ledDevice, 4, "$ledDevice->{NAME} low level cmd queue send $dbgStr, qlen ".@{$ledDevice->{helper}->{llCmdQueue}}." connection refused: trying to reconnect");
  3524. if ($ledDevice->{helper}->{SOCKET}) {
  3525. $ledDevice->{helper}->{SOCKET}->shutdown(2);
  3526. $ledDevice->{helper}->{SOCKET}->close();
  3527. }
  3528. $ledDevice->{helper}->{SOCKET} = IO::Socket::INET-> new (
  3529. PeerPort => $ledDevice->{PORT},
  3530. PeerAddr => $ledDevice->{IP},
  3531. Timeout => 1,
  3532. Blocking => 0,
  3533. Proto => 'tcp') or Log3 ($ledDevice, 3, "$ledDevice->{NAME} low level cmd queue send ERROR $dbgStr, qlen ".@{$ledDevice->{helper}->{llCmdQueue}}." (reconnect giving up)");
  3534. $ledDevice->{helper}->{SELECT} = IO::Select->new($ledDevice->{helper}->{SOCKET}) if $ledDevice->{helper}->{SOCKET};
  3535. }
  3536. $ledDevice->{helper}->{SOCKET}->send($actualCmd->{command}) if $ledDevice->{helper}->{SOCKET};
  3537. }
  3538. else
  3539. {
  3540. # print "send: $ledDevice->{NAME} $dbgStr \n";
  3541. send($ledDevice->{helper}->{SOCKET}, $actualCmd->{command}, 0, $actualCmd->{receiver}) or Log3 ($ledDevice, 1, "$ledDevice->{NAME} low level cmd queue send ERROR $@ $dbgStr, qlen ".@{$ledDevice->{helper}->{llCmdQueue}});
  3542. }
  3543. $actualCmd->{inProgess} = 1;
  3544. my $msec = $actualCmd->{delay} / 1000;
  3545. InternalTimer(gettimeofday()+$msec, "WifiLight_LowLevelCmdQueue_Send", $ledDevice, 0);
  3546. return undef;
  3547. }
  3548. 1;
  3549. =pod
  3550. =item device
  3551. =item summary controls a large number of different LED types
  3552. =item summary_DE steuert eine gro&szlig;e Anzahl unterschiedlicher LED Typen
  3553. =begin html
  3554. <a name="WifiLight"></a>
  3555. <h3>WifiLight</h3>
  3556. <ul>
  3557. <p>The module controls a large number of different "no name" LED types and provide a consistent interface.</p>
  3558. <p>Following types will be supported:</p>
  3559. <!-- <table rules="all" cellpadding="6" style="border:solid 1px;"> -->
  3560. <table>
  3561. <thead align="left">
  3562. <tr>
  3563. <th>
  3564. type / bridge
  3565. </th>
  3566. <th>
  3567. type
  3568. </th>
  3569. <th>
  3570. note
  3571. </th>
  3572. <th>
  3573. define signature
  3574. </th>
  3575. </tr>
  3576. </thead>
  3577. <tbody>
  3578. <tr>
  3579. <td>
  3580. Milight RGB first generation
  3581. </td>
  3582. <td>
  3583. E27, stripe controller
  3584. </td>
  3585. <td>
  3586. *(1,2,a,C)
  3587. </td>
  3588. <td>
  3589. RGB bridge-V2|3
  3590. </td>
  3591. </tr>
  3592. <tr>
  3593. <td>
  3594. Milight RGBW1 first generation
  3595. </td>
  3596. <td>
  3597. RGBW stripe controller
  3598. </td>
  3599. <td>
  3600. *(1,2,a)
  3601. </td>
  3602. <td>
  3603. RGBW1 bridge-V2|3
  3604. </td>
  3605. </tr>
  3606. <tr>
  3607. <td>
  3608. Milight Dual White
  3609. </td>
  3610. <td>
  3611. E14, E27, GU10, stripe controller, Downlight
  3612. </td>
  3613. <td>
  3614. *(1,2,b,W,nK)
  3615. </td>
  3616. <td>
  3617. White bridge-V2|3
  3618. </td>
  3619. </tr>
  3620. <tr>
  3621. <td>
  3622. Milight RGBW2 second generation
  3623. </td>
  3624. <td>
  3625. E14, E27, GU10, stripe controller, Downlight
  3626. </td>
  3627. <td>
  3628. *(2,b,CW,S20)
  3629. </td>
  3630. <td>
  3631. RGBW2 bridge-V3
  3632. </td>
  3633. </tr>
  3634. <tr>
  3635. <td>
  3636. LW12 first generation (SSID LEDNet...)
  3637. </td>
  3638. <td>
  3639. RGB stripe controller
  3640. </td>
  3641. <td>
  3642. &nbsp;
  3643. </td>
  3644. <td>
  3645. RGB LW12
  3646. </td>
  3647. </tr>
  3648. <tr>
  3649. <td>
  3650. LW12HX (SSID HX...)
  3651. </td>
  3652. <td>
  3653. RGB stripe controller
  3654. </td>
  3655. <td>
  3656. &nbsp;
  3657. </td>
  3658. <td>
  3659. RGB LW12HX
  3660. </td>
  3661. </tr>
  3662. <tr>
  3663. <td>
  3664. LW12FC (SSID FC...)
  3665. </td>
  3666. <td>
  3667. RGB stripe controller
  3668. </td>
  3669. <td>
  3670. &nbsp;
  3671. </td>
  3672. <td>
  3673. RGB LW12FC
  3674. </td>
  3675. </tr>
  3676. <tr>
  3677. <td>
  3678. LD316 in RGB mode
  3679. </td>
  3680. <td>
  3681. E27
  3682. </td>
  3683. <td>
  3684. &nbsp;
  3685. </td>
  3686. <td>
  3687. RGB LD316
  3688. </td>
  3689. </tr>
  3690. <tr>
  3691. <td>
  3692. LD316 in RGBW mode
  3693. </td>
  3694. <td>
  3695. E27
  3696. </td>
  3697. <td>
  3698. *(S20)
  3699. </td>
  3700. <td>
  3701. RGBW LD316
  3702. </td>
  3703. </tr>
  3704. <tr>
  3705. <td>
  3706. LD316A in RGBW mode
  3707. </td>
  3708. <td>
  3709. E27
  3710. </td>
  3711. <td>
  3712. *(S20)
  3713. </td>
  3714. <td>
  3715. RGBW LD316A
  3716. </td>
  3717. </tr>
  3718. <tr>
  3719. <td>
  3720. LD382 in RGB mode
  3721. </td>
  3722. <td>
  3723. RGB stripe controller
  3724. </td>
  3725. <td>
  3726. &nbsp;
  3727. </td>
  3728. <td>
  3729. RGB LD382
  3730. </td>
  3731. </tr>
  3732. <tr>
  3733. <td>
  3734. LD382 in RGBW mode
  3735. </td>
  3736. <td>
  3737. RGBW stripe controller
  3738. </td>
  3739. <td>
  3740. &nbsp;
  3741. </td>
  3742. <td>
  3743. RGBW LD382
  3744. </td>
  3745. </tr>
  3746. <tr>
  3747. <td>
  3748. LD382A (FW 1.0.6+) in RGB mode
  3749. </td>
  3750. <td>
  3751. RGB stripe controller
  3752. </td>
  3753. <td>
  3754. &nbsp;
  3755. </td>
  3756. <td>
  3757. RGB LD382
  3758. </td>
  3759. </tr>
  3760. <tr>
  3761. <td>
  3762. LD382A (FW 1.0.6+) in RGBW mode
  3763. </td>
  3764. <td>
  3765. RGBW stripe controller
  3766. </td>
  3767. <td>
  3768. &nbsp;
  3769. </td>
  3770. <td>
  3771. RGBW LD382
  3772. </td>
  3773. </tr>
  3774. <tr>
  3775. <td>
  3776. SENGLED
  3777. </td>
  3778. <td>
  3779. E27 bulb with build-in WLAN repeater
  3780. </td>
  3781. <td>
  3782. &nbsp;
  3783. </td>
  3784. <td>
  3785. White Sengled
  3786. </td>
  3787. </tr>
  3788. <tr>
  3789. <td>
  3790. SUNRICHER with RGBW
  3791. </td>
  3792. <td>
  3793. Controller
  3794. </td>
  3795. <td>
  3796. *(!!!)
  3797. </td>
  3798. <td>
  3799. RGBW Sunricher
  3800. </td>
  3801. </tr>
  3802. </tbody>
  3803. </table>
  3804. <p>
  3805. <small>
  3806. (1) milght brigbe V2, V3, V4<br />
  3807. (2) milight bridge V3, V4<br />
  3808. (a) one group per bridge<br />
  3809. (b) four independent group per bridge<br />
  3810. (nK) no color temp support (Kelvin)<br />
  3811. (C) pure color<br />
  3812. (W) pure white<br />
  3813. (CW) pure Color or pure white<br />
  3814. (S20) Saturation &lt;20: switch to pure white channel<br />
  3815. (!!!) EXPERIMENTAL<br />
  3816. </p>
  3817. </small>
  3818. <p>
  3819. <table>
  3820. <tr>
  3821. <td>
  3822. <p><b>Color</b></p>
  3823. <p>Colors can be specified in RGB or HSV color space.</p>
  3824. <p>Color in <a name="WifiLight_Farbraum_HSV"><b>color space "HSV"</b></a> are completely and generally more intuitive than RGB.</p>
  3825. <p><b>H</b> (HUE: 0..360) are the basic color in a color wheel.
  3826. <ul>
  3827. <li>Red is at 0 °</li>
  3828. <li>Green at 120 °</li>
  3829. <li> Blue at 240 °</li>
  3830. </ul>
  3831. </p>
  3832. <p><b>S</b> (Saturation: 0..100) stands for the saturation of the color. A saturation of 100 means the color is "pure" or completely saturated. Blue, for example, with 100% saturation corresponds to RGB # 0000FF.</p>
  3833. <p><b>V</b> (Value: 0..100) indicates the brightness. A value of 50 states that "half brightness".</p>
  3834. </td>
  3835. <td>
  3836. <a name="WifiLight_Farbkreis">
  3837. <svg style="width:450px; height:320px;" viewBox="-100 -30 500 320">
  3838. <linearGradient id="linearColors1" x1="0" y1="0" x2="1" y2="1">
  3839. <stop offset="0%" stop-color="#FF0000"></stop>
  3840. <stop offset="100%" stop-color="#FFFF00"></stop>
  3841. </linearGradient>
  3842. <linearGradient id="linearColors2" x1="0.5" y1="0" x2="0.5" y2="1">
  3843. <stop offset="0%" stop-color="#FFFF00"></stop>
  3844. <stop offset="100%" stop-color="#00FF00"></stop>
  3845. </linearGradient>
  3846. <linearGradient id="linearColors3" x1="1" y1="0" x2="0" y2="1">
  3847. <stop offset="0%" stop-color="#00FF00"></stop>
  3848. <stop offset="100%" stop-color="#00FFFF"></stop>
  3849. </linearGradient>
  3850. <linearGradient id="linearColors4" x1="1" y1="1" x2="0" y2="0">
  3851. <stop offset="0%" stop-color="#00FFFF"></stop>
  3852. <stop offset="100%" stop-color="#0000FF"></stop>
  3853. </linearGradient>
  3854. <linearGradient id="linearColors5" x1="0.5" y1="1" x2="0.5" y2="0">
  3855. <stop offset="0%" stop-color="#0000FF"></stop>
  3856. <stop offset="100%" stop-color="#FF00FF"></stop>
  3857. </linearGradient>
  3858. <linearGradient id="linearColors6" x1="0" y1="1" x2="1" y2="0">
  3859. <stop offset="0%" stop-color="#FF00FF"></stop>
  3860. <stop offset="100%" stop-color="#FF0000"></stop>
  3861. </linearGradient>
  3862. <linearGradient id="linearColors7" x1="152" y1="130" x2="152" y2="35" gradientUnits="userSpaceOnUse">
  3863. <stop offset="0.2" stop-color="#FFFFFF"></stop>
  3864. <stop offset="1" stop-color="#FF0000"></stop>
  3865. </linearGradient>
  3866. <linearGradient id="linearColors8" x1="152" y1="130" x2="230" y2="190" gradientUnits="userSpaceOnUse">
  3867. <stop offset="0.2" stop-color="#FFFFFF"></stop>
  3868. <stop offset="1" stop-color="#00FF00"></stop>
  3869. </linearGradient>
  3870. <linearGradient id="linearColors9" x1="152" y1="130" x2="70" y2="190" gradientUnits="userSpaceOnUse">
  3871. <stop offset="0.2" stop-color="#FFFFFF"></stop>
  3872. <stop offset="1" stop-color="#0000FF"></stop>
  3873. </linearGradient>
  3874. <marker id="markerArrow" markerWidth="13" markerHeight="13" refX="2" refY="6" orient="auto">
  3875. <path d="M2,2 L2,11 L10,6 L2,2" style="fill:grey;" />
  3876. </marker>
  3877. <path d="M150 10 a120 120 0 0 1 103.9230 60" fill="none" stroke="url(#linearColors1)" stroke-width="20" />
  3878. <path d="M253.9230 70 a120 120 0 0 1 0 120" fill="none" stroke="url(#linearColors2)" stroke-width="20" />
  3879. <path d="M253.9230 190 a120 120 0 0 1 -103.9230 60" fill="none" stroke="url(#linearColors3)" stroke-width="20" />
  3880. <path d="M150 250 a120 120 0 0 1 -103.9230 -60" fill="none" stroke="url(#linearColors4)" stroke-width="20" />
  3881. <path d="M46.077 190 a120 120 0 0 1 0 -120" fill="none" stroke="url(#linearColors5)" stroke-width="20" />
  3882. <path d="M46.077 70 a120 120 0 0 1 103.9230 -60" fill="none" stroke="url(#linearColors6)" stroke-width="20" />
  3883. <path d="M150,50 C250,50 250,180 180,200" fill="none" stroke="grey" stroke-width="2" marker-end="url(#markerArrow)" />
  3884. <text class="Label" x="126" y="208">HUE</text>
  3885. <line x1="152" y1="130" x2="152" y2="35" stroke="url(#linearColors7)" stroke-width="4" />
  3886. <line x1="136" y1="120" x2="136" y2="45" stroke="grey" stroke-width="2" marker-end="url(#markerArrow)" />
  3887. <text class="Label" x="96" y="96">SAT</text>
  3888. <line x1="152" y1="130" x2="230" y2="190" stroke="url(#linearColors8)" stroke-width="4" />
  3889. <line x1="152" y1="130" x2="70" y2="190" stroke="url(#linearColors9)" stroke-width="4" />
  3890. <text x="120" y="-10">0° (Red)</text>
  3891. <text x="270" y="60">60° (Yellow)</text>
  3892. <text x="270" y="220">120° (Green)</text>
  3893. <text x="110" y="285">180° (Cyan)</text>
  3894. <text x="-60" y="220">240° (Blue)</text>
  3895. <text x="-90" y="60">300° (Magenta)</text>
  3896. </svg>
  3897. </a>
  3898. </td>
  3899. </tr>
  3900. </table>
  3901. </p>
  3902. <p>
  3903. <b>Color: HSV compared to RGB</b>
  3904. <p>
  3905. Normally, a color may be expressed in the HSV color space as well as in RGB color space.
  3906. <p>
  3907. Colors in the HSV color space usually seem more understandable.
  3908. To move a Green in the HSV color space a little more toward CYAN, simply increase the HUE value (angle) slightly.
  3909. In RGB color space, the same task is less intuitive to achieve by increasing blue.
  3910. <p>
  3911. Differences become clear in Transitions however.
  3912. In order to dim BLUE up the HSV Transitions 240,100,0 -> 240,100,100 would be used.
  3913. To slowly dim RED (brightness 0) to BLUE the Transition in the HSV color space is 0,100,0 -> 240,100,100.
  3914. In RGB color space (# 000000 -> # 0000FF) can not distinguish between the two versions.
  3915. Here (correctly, but probably differently than intended) would appear in both cases, a white (brightness 0) as an initial value.
  3916. </p>
  3917. <p><b>Define</b></p>
  3918. <ul>
  3919. <li>
  3920. <p><code>define &lt;name&gt; WifiLight &lt;LED type&gt; &lt;bridgetype&gt;:&lt;IP|FQDN&gt;</code></p>
  3921. <p>
  3922. <i><u>example</u></i>
  3923. <ul>
  3924. <p>
  3925. <i>defines a milight RGBW2 (bulb or LED stripe controller) on a milight bridge version 3 or 4.
  3926. The LED is allocated to a maximum of 4 groups available per bridge in order of definition:</i>
  3927. <br/>
  3928. <code>define wz.licht.decke WifiLight RGBW2 bridge-V3:192.168.178.142</code>
  3929. </ul>
  3930. <ul>
  3931. <p>
  3932. <i>defines a LD382A Controller with RGBW stripe:</i>
  3933. <br/>
  3934. <code>define wz.licht.decke WifiLight RGBW LD382A:192.168.178.142</code>
  3935. </ul>
  3936. <ul>
  3937. <p>
  3938. <i>defines a LD382A Controller with RGB stripe:</i>
  3939. <br/>
  3940. <code>define wz.licht.decke WifiLight RGB LD382A:192.168.178.142</code>
  3941. </ul>
  3942. <p>WifiLight has a <a href="#WifiLight_Farbkalibrierung">"color calibration"</a>. Ideally, a calibration should be performed every time after a lamp change or after definition.</p>
  3943. </ul>
  3944. </li>
  3945. <p><b>Set</b></p>
  3946. <ul>
  3947. <li>
  3948. <p><code>set &lt;name&gt; <b>on</b> [ramp]</code></p>
  3949. <p>Turns on the device. It is either chosen 100% White or the color defined by the attribute "default color".
  3950. <p>Advanced options:
  3951. <ul>
  3952. <li>ramp</li>
  3953. </ul>
  3954. </p>
  3955. </li>
  3956. <li>
  3957. <p><code>set &lt;name&gt; <b>off</b> [ramp]</code></p>
  3958. <p>Turns of the device.
  3959. <p>Advanced options:
  3960. <ul>
  3961. <li>ramp</li>
  3962. </ul>
  3963. </p>
  3964. </li>
  3965. <li>
  3966. <p><code>set &lt;name&gt; <b>dimup</b></code></p>
  3967. <p>Increases the brightness by a fixed amount. The attribute "dimStep" or the default "7" is applied.<br />
  3968. This command is useful to increase particularly the brightness by a wall switch or a remote control.
  3969. <p>Advanced options:
  3970. <ul>
  3971. <li>none</li>
  3972. </ul>
  3973. </p>
  3974. </li>
  3975. <li>
  3976. <p><code>set &lt;name&gt; <b>dimdown</b></code></p>
  3977. <p>Decreases the brightness by a fixed amount. The attribute "dimStep" or the default "7" is applied.<br />
  3978. This command is useful to reduce particularly the brightness by a wall switch or a remote control.
  3979. <p>Advanced options:
  3980. <ul>
  3981. <li>none</li>
  3982. </ul>
  3983. </p>
  3984. </li>
  3985. <li>
  3986. <p><code>set &lt;name&gt; <b>dim</b> level [ramp] [q]</code></p>
  3987. <p>Sets the brightness to the specified level (0..100).
  3988. This command also maintains the preset color even with "dim 0" (off) and then "dim xx" (turned on) at.
  3989. Therefore, it represents an alternative form to "off" / "on". The latter would always choose the "default color".
  3990. <p>Advanced options:
  3991. <ul>
  3992. <li>ramp</li>
  3993. </ul>
  3994. </p>
  3995. <p>Flags:
  3996. <ul>
  3997. <li>q</li>
  3998. </ul>
  3999. </p>
  4000. </li>
  4001. <li>
  4002. <p><code>set &lt;name&gt; <b>HSV</b> H,S,V [ramp] [s|l|q] [event]</code></p>
  4003. <p>Sets the color in the <a href="#WifiLight_Farbraum_HSV">HSV color space</a>. If the ramp is specified (as a time in seconds), the module calculates a soft color transition from the current color to the newly set.
  4004. <ul><i>For example, sets a saturated blue with half brightness:</i><br /><code>set wz.licht.decke HSV 240,100,50</code></ul>
  4005. <p>Advanced options:
  4006. <ul>
  4007. <li>ramp</li>
  4008. </ul>
  4009. </p>
  4010. <p>Flags:
  4011. <ul>
  4012. <li>s l q event</li>
  4013. </ul>
  4014. </p>
  4015. </li>
  4016. <li>
  4017. <p><code>set &lt;name&gt; <b>RGB</b> RRGGBB [ramp] [l|s|q] [event]</code></p>
  4018. <p>Sets the color in the RGB color space.
  4019. <p>Advanced options:
  4020. <ul>
  4021. <li>ramp</li>
  4022. </ul>
  4023. </p>
  4024. <p>Flags:
  4025. <ul>
  4026. <li>s l q event</li>
  4027. </ul>
  4028. </p>
  4029. </ul>
  4030. </li>
  4031. <p><b>Meaning of Flags</b></p>
  4032. Certain commands (set) can be marked with special flags.
  4033. <p>
  4034. <ul>
  4035. <li>ramp:
  4036. <ul>
  4037. Time in seconds for a soft color or brightness transition. The soft transition starts at the currently visible color and is calculated for the specified.
  4038. </ul>
  4039. </li>
  4040. <li>s:
  4041. <ul>
  4042. (short, default). A smooth transition to another color is carried out in the <a href="#WifiLight_Farbkreis">"color wheel"</a> on the shortest path.
  4043. A transition from red to green lead by the shortest route through yellow.
  4044. </ul>
  4045. </li>
  4046. <li>l:
  4047. <ul>
  4048. (long). A smooth transition to another color is carried out in the <a href="#WifiLight_Farbkreis">"color wheel"</a> on the "long" way.
  4049. A transition from red to green then leads across magenta, blue, and cyan.
  4050. </ul>
  4051. </li>
  4052. <li>q:
  4053. <ul>
  4054. (queue). Commands with this flag are cached in an internal queue and will not run before the currently running soft transitions have been processed.
  4055. Commands without the flag will be processed immediately. In this case all running transitions are stopped immediately and the queue will be cleared.
  4056. </ul>
  4057. </li>
  4058. <li>event:
  4059. <ul>
  4060. designator ([A-Za-z_0-9])
  4061. <p>
  4062. WifiLight creates, when using this flag, during transitions to another color messages (events) in the form:
  4063. <p>
  4064. <code>WifiLight &ltNAME&gt programm: &ltEVENT&gt &ltXX&gt</code>.
  4065. <p>
  4066. &ltEVENT&gt is the designator as specified in the flag.<br/>
  4067. &ltXX&gt is the progress (percentage) of the transition.<br/>
  4068. <p>
  4069. Depending on the total duration of the transition, the values from 0 to 100 will not completely go through but for 0% and 100% is guaranteed always a event.
  4070. To these events can then be reacted within a notify or DOIF to (for example):
  4071. <ul>
  4072. <li>increase the volume of a radio when a lamp is turned on in the morning slowly</li>
  4073. <li>A color transition can be restarted in a notify if it is complete (loop it, even complex transitions)</li>
  4074. <li>Other light sources can be synchronized by individually created color transitions.</li>
  4075. </ul>
  4076. </ul>
  4077. </li>
  4078. </ul>
  4079. <p><b><a name="WifiLight_Farbkalibrierung"></a>color calibration</b></p>
  4080. WifiLight supports two different types of color calibrations:
  4081. <ul>
  4082. <p>
  4083. <b>Correction of saturated colors</b>
  4084. <p>
  4085. background:
  4086. <p>
  4087. YELLOW, for example, is defined as a mixture of red and green light in equal parts.
  4088. Depending on the LED and control used the green channel may be much more luminous.
  4089. If the red and green LEDs are each fully driven, GREEN predominates in this mixture and the desired YELLOW would get a distinct green tint.
  4090. In this example, no yellow would be generated (corresponding to 60 ° in the <a href="#WifiLight_Farbkreis">"color wheel"</a>) for HSV 60,100,100.
  4091. Instead GREEN would be generated with yellow tinge, perhaps corresponding to an estimated color angle of 80 °.
  4092. The required correction for yellow would therefore minus 20° (60° target - 80° result = -20° correction).
  4093. YELLOW may have to be corrected as to -20 °. Possible values per correction point are +/- 29 °.
  4094. <p>
  4095. procedure:
  4096. <p>
  4097. The correction of the full color is controlled by the attribute "color cast".
  4098. Here 6 (comma separated) values are specified in the range from -29 to 29.
  4099. These values are in accordance with the angle correction for red (0 °), yellow (60 °), green (120 °), cyan (180 °), blue (240 °) and magenta (300 °).
  4100. First, the deviation of the mixed colors (60 ° / 180 ° / 300 °) should be determined as in the above example, and stored in the attribute.
  4101. Following the primary colors (0 ° / 120 ° / 240 °) should be corrected so that the smooth transitions between adjacent pure colors appear as linear as possible.
  4102. This process may need to be repeated iteratively multiple times until the result is harmonious.
  4103. <p>
  4104. <b>White Balance</b>
  4105. <p>
  4106. background:
  4107. <p>
  4108. Some bulbs produce white light by mixing the RGB channels (for example, LW12).
  4109. Depending on the light intensity of the RGB channels of the LED strips used, the result is different.
  4110. One or two colors dominate.
  4111. In addition, there are various types of white light.
  4112. Cold light has a higher proportion of blue.
  4113. In Central Europe mostly warm white light is used for light sources.
  4114. This has a high red and low blue component.
  4115. <p>
  4116. WifiLight offers the possibility for mixed RGB white to adapt the composition.
  4117. The adjustment is carried out via the attribute "white point".
  4118. The attribute expects a value between 0 and 1 (decimal point with) and the three colors are separated by a comma for each of the three RGB channels.
  4119. <p>
  4120. procedure:
  4121. <p>
  4122. A value of "1,1,1" sets all the three channels to 100% each.
  4123. Assuming that the blue component of the white light should be reduced, a value of "1,1,0.5" sets the third channel (BLUE) in white on 0.5 according to 50%.
  4124. Before doing a white balance correction the adjusment of the saturated color should be completed.
  4125. </ul>
  4126. <p><b>Attribute</b></p>
  4127. <ul>
  4128. <li>
  4129. <code>attr &ltname&gt <b>colorCast</b> &ltR,Y,G,C,B,M&gt</code>
  4130. <p>
  4131. <a href="#WifiLight_Farbkalibrierung">color calibration</a> of saturated colors.
  4132. R(ed), Y(ellow), G(reen), C(yan), B(lue), M(agenta) in the range of +/- 29 (degrees)
  4133. </li>
  4134. <li>
  4135. <code>attr &ltname&gt <b>defaultColor</b> &ltH,S,V&gt</code>
  4136. <p>
  4137. Specify the light color in HSV which is selected at "on". Default is white.
  4138. </li>
  4139. <li>
  4140. <code>attr &ltname&gt <b>defaultRamp</b> &lt0 bis X&gt</code>
  4141. <p>
  4142. Time in seconds. If this attribute is set, a smooth transition is always implicitly generated if no ramp in the set is indicated.
  4143. </li>
  4144. <li>
  4145. <code>attr &ltname&gt <b>dimStep</b> &lt0 bis 100&gt</code>
  4146. <p>
  4147. Value by which the brightness at dim up and dim-down is changed. Default is "7"
  4148. </li>
  4149. <li>
  4150. <code>attr &ltname&gt <b>gamma</b> &ltX.X&gt</code>
  4151. <p>
  4152. The human eye perceives brightness changes very differently to (logarithmic).
  4153. At low output brightness even a small change in brightness is perceived as very strong and on the other side strong changes are needed at high luminance.
  4154. Therefore, a logarithmic correction of brightness increase of lamps is necessary so that the increase is found to be uniform.
  4155. Some controllers perform this correction internally.
  4156. In other cases it is necessary to store this correction in the module.
  4157. A gamma value of 1.0 (default) results in a linear output values.
  4158. Values less than 1.0 lead to a logarithmic correction.
  4159. </li>
  4160. <li>
  4161. <code>attr &ltname&gt <b>whitePoint</b> &ltR,G,B&gt</code>
  4162. <p>
  4163. <a href="#WifiLight_Farbkalibrierung">color calibration</a> for mixed RGB white light.
  4164. </li>
  4165. <li>
  4166. <code>attr &ltname&gt <b><a href="#readingFnAttributes">readingFnAttributes</a></b></code>
  4167. </li>
  4168. </ul>
  4169. <p><b>Colored device-icon for FhemWeb</b>
  4170. <ul>
  4171. <p>
  4172. To activate a colored icon for <a href="#FHEMWEB">FhemWeb</a> the following attribute must be set:
  4173. <p>
  4174. <li>
  4175. <code>attr &ltname&gt <b>devStateIcon</b> {Color_devStateIcon(ReadingsVal($name,"RGB","000000"))}</code>
  4176. </li>
  4177. </ul>
  4178. <p><b>Colorpicker for FhemWeb</b>
  4179. <ul>
  4180. <p>
  4181. In order for the Color Picker can be used in <a href="#FHEMWEB">FhemWeb</a> following attributes need to be set:
  4182. <p>
  4183. <li>
  4184. <code>attr &ltname&gt <b>webCmd</b> RGB</code>
  4185. </li>
  4186. <li>
  4187. <code>attr &ltname&gt <b>widgetOverride</b> RGB:colorpicker,RGB</code>
  4188. </li>
  4189. </ul>
  4190. </ul>
  4191. =end html
  4192. =begin html_DE
  4193. <a name="WifiLight"></a>
  4194. <h3>WifiLight</h3>
  4195. <ul>
  4196. <p>Das Modul steuert eine gro&szlig;e Anzahl unterschiedlicher &quot;no name&quot; LED Typen und stellt Ihnen einheitliches Interface zur Verf&uuml;gung.</p>
  4197. <p>Folgende Typen werden unterstützt:</p>
  4198. <!-- <table rules="all" cellpadding="6" style="border:solid 1px;"> -->
  4199. <table>
  4200. <thead align="left">
  4201. <tr>
  4202. <th>
  4203. Leuchtmitteltyp / bridge
  4204. </th>
  4205. <th>
  4206. Type
  4207. </th>
  4208. <th>
  4209. Notiz
  4210. </th>
  4211. <th>
  4212. Signatur im define
  4213. </th>
  4214. </tr>
  4215. </thead>
  4216. <tbody>
  4217. <tr>
  4218. <td>
  4219. Milight RGB erste Generation
  4220. </td>
  4221. <td>
  4222. E27, stripe controller
  4223. </td>
  4224. <td>
  4225. *(1,2,a,C)
  4226. </td>
  4227. <td>
  4228. RGB bridge-V2|3
  4229. </td>
  4230. </tr>
  4231. <tr>
  4232. <td>
  4233. Milight RGBW1 erste Generation
  4234. </td>
  4235. <td>
  4236. RGBW stripe controller
  4237. </td>
  4238. <td>
  4239. *(1,2,a)
  4240. </td>
  4241. <td>
  4242. RGBW1 bridge-V2|3
  4243. </td>
  4244. </tr>
  4245. <tr>
  4246. <td>
  4247. Milight White
  4248. </td>
  4249. <td>
  4250. E14, E27, GU10, stripe controller, Downlight
  4251. </td>
  4252. <td>
  4253. *(1,2,b,W,nK)
  4254. </td>
  4255. <td>
  4256. White bridge-V2|3
  4257. </td>
  4258. </tr>
  4259. <tr>
  4260. <td>
  4261. Milight RGBW2 zweite Generation
  4262. </td>
  4263. <td>
  4264. E14, E27, GU10, stripe controller, Downlight
  4265. </td>
  4266. <td>
  4267. *(2,b,CW,S20)
  4268. </td>
  4269. <td>
  4270. RGBW2 bridge-V3
  4271. </td>
  4272. </tr>
  4273. <tr>
  4274. <td>
  4275. LW12 erste Generation (SSID LEDNet...)
  4276. </td>
  4277. <td>
  4278. RGB stripe controller
  4279. </td>
  4280. <td>
  4281. &nbsp;
  4282. </td>
  4283. <td>
  4284. RGB LW12
  4285. </td>
  4286. </tr>
  4287. <tr>
  4288. <td>
  4289. LW12HX (SSID HX...)
  4290. </td>
  4291. <td>
  4292. RGB stripe controller
  4293. </td>
  4294. <td>
  4295. &nbsp;
  4296. </td>
  4297. <td>
  4298. RGB LW12HX
  4299. </td>
  4300. </tr>
  4301. <tr>
  4302. <td>
  4303. LW12FC (SSID FC...)
  4304. </td>
  4305. <td>
  4306. RGB stripe controller
  4307. </td>
  4308. <td>
  4309. &nbsp;
  4310. </td>
  4311. <td>
  4312. RGB LW12FC
  4313. </td>
  4314. </tr>
  4315. <tr>
  4316. <td>
  4317. LD316 im RGB mode
  4318. </td>
  4319. <td>
  4320. E27
  4321. </td>
  4322. <td>
  4323. &nbsp;
  4324. </td>
  4325. <td>
  4326. RGB LD316
  4327. </td>
  4328. </tr>
  4329. <tr>
  4330. <td>
  4331. LD316 im RGBW mode
  4332. </td>
  4333. <td>
  4334. E27
  4335. </td>
  4336. <td>
  4337. *(S20)
  4338. </td>
  4339. <td>
  4340. RGBW LD316
  4341. </td>
  4342. </tr>
  4343. <tr>
  4344. <td>
  4345. LD316A im RGBW mode
  4346. </td>
  4347. <td>
  4348. E27
  4349. </td>
  4350. <td>
  4351. *(S20)
  4352. </td>
  4353. <td>
  4354. RGBW LD316A
  4355. </td>
  4356. </tr>
  4357. <tr>
  4358. <td>
  4359. LD382 im RGB mode
  4360. </td>
  4361. <td>
  4362. RGB stripe controller
  4363. </td>
  4364. <td>
  4365. &nbsp;
  4366. </td>
  4367. <td>
  4368. RGB LD382
  4369. </td>
  4370. </tr>
  4371. <tr>
  4372. <td>
  4373. LD382 im RGBW mode
  4374. </td>
  4375. <td>
  4376. RGBW stripe controller
  4377. </td>
  4378. <td>
  4379. &nbsp;
  4380. </td>
  4381. <td>
  4382. RGBW LD382
  4383. </td>
  4384. </tr>
  4385. <tr>
  4386. <td>
  4387. LD382A (FW 1.0.6) im RGB mode
  4388. </td>
  4389. <td>
  4390. RGB stripe controller
  4391. </td>
  4392. <td>
  4393. &nbsp;
  4394. </td>
  4395. <td>
  4396. RGB LD382
  4397. </td>
  4398. </tr>
  4399. <tr>
  4400. <td>
  4401. LD382A (FW 1.0.6) im RGBW mode
  4402. </td>
  4403. <td>
  4404. RGBW stripe controller
  4405. </td>
  4406. <td>
  4407. &nbsp;
  4408. </td>
  4409. <td>
  4410. RGBW LD382
  4411. </td>
  4412. </tr>
  4413. <tr>
  4414. <td>
  4415. SENGLED
  4416. </td>
  4417. <td>
  4418. E27 mit WLAN repeater
  4419. </td>
  4420. <td>
  4421. &nbsp;
  4422. </td>
  4423. <td>
  4424. White Sengled
  4425. </td>
  4426. </tr>
  4427. <tr>
  4428. <td>
  4429. SUNRICHER mit RGBW
  4430. </td>
  4431. <td>
  4432. Controller
  4433. </td>
  4434. <td>
  4435. *(!!!)
  4436. </td>
  4437. <td>
  4438. RGBW Sunricher
  4439. </td>
  4440. </tr>
  4441. </tbody>
  4442. </table>
  4443. <p>
  4444. <small>
  4445. (1) milght brigbe V2, V3, V4<br />
  4446. (2) milight bridge V3, V4<br />
  4447. (a) eine Gruppe pro bridge<br />
  4448. (b) vier unabh&auml;ngige Gruppen pro bridge<br />
  4449. (nK) kein Temperatursupport, Kelvin<br />
  4450. (C) rein Color<br />
  4451. (W) rein White<br />
  4452. (CW) rein Color oder White<br />
  4453. (S20) Saturation &lt;20: umschalten white Channel<br />
  4454. (!!!) EXPERIMENTAL<br />
  4455. </p>
  4456. </small>
  4457. <p>
  4458. <table>
  4459. <tr>
  4460. <td>
  4461. <p><b>Farbangaben</b></p>
  4462. <p>Farben können im RGB oder im HSV Farbraum angegeben werden.</p>
  4463. <p>Farbangaben im <a name="WifiLight_Farbraum_HSV"><b>Farbraum "HSV"</b></a> sind vollständig und in der Regel intuitiver als RGB.</p>
  4464. <p><b>H</b> (HUE: 0..360) gibt die Grundfarbe in einem Farbkreis an.
  4465. <ul>
  4466. <li>Rot liegt bei 0°</li>
  4467. <li>Grün bei 120°</li>
  4468. <li>Blau bei 240°</li>
  4469. </ul>
  4470. </p>
  4471. <p><b>S</b> (Saturation/Sättigung: 0..100) steht für die Sättigung der Farbe. Eine Sättigung von 100 bedeutet die Farbe ist "rein" oder komplett gesättigt. Blau zum Beispiel mit 100% Sättigung entspricht RGB #0000FF.</p>
  4472. <p><b>V</b> (Value: 0..100) gibt die Helligkeit an. Ein V von 50 heißt: "halbe Helligkeit".</p>
  4473. </td>
  4474. <td>
  4475. <a name="WifiLight_Farbkreis">
  4476. <svg style="width:450px; height:320px;" viewBox="-100 -30 500 320">
  4477. <linearGradient id="linearColors1" x1="0" y1="0" x2="1" y2="1">
  4478. <stop offset="0%" stop-color="#FF0000"></stop>
  4479. <stop offset="100%" stop-color="#FFFF00"></stop>
  4480. </linearGradient>
  4481. <linearGradient id="linearColors2" x1="0.5" y1="0" x2="0.5" y2="1">
  4482. <stop offset="0%" stop-color="#FFFF00"></stop>
  4483. <stop offset="100%" stop-color="#00FF00"></stop>
  4484. </linearGradient>
  4485. <linearGradient id="linearColors3" x1="1" y1="0" x2="0" y2="1">
  4486. <stop offset="0%" stop-color="#00FF00"></stop>
  4487. <stop offset="100%" stop-color="#00FFFF"></stop>
  4488. </linearGradient>
  4489. <linearGradient id="linearColors4" x1="1" y1="1" x2="0" y2="0">
  4490. <stop offset="0%" stop-color="#00FFFF"></stop>
  4491. <stop offset="100%" stop-color="#0000FF"></stop>
  4492. </linearGradient>
  4493. <linearGradient id="linearColors5" x1="0.5" y1="1" x2="0.5" y2="0">
  4494. <stop offset="0%" stop-color="#0000FF"></stop>
  4495. <stop offset="100%" stop-color="#FF00FF"></stop>
  4496. </linearGradient>
  4497. <linearGradient id="linearColors6" x1="0" y1="1" x2="1" y2="0">
  4498. <stop offset="0%" stop-color="#FF00FF"></stop>
  4499. <stop offset="100%" stop-color="#FF0000"></stop>
  4500. </linearGradient>
  4501. <linearGradient id="linearColors7" x1="152" y1="130" x2="152" y2="35" gradientUnits="userSpaceOnUse">
  4502. <stop offset="0.2" stop-color="#FFFFFF"></stop>
  4503. <stop offset="1" stop-color="#FF0000"></stop>
  4504. </linearGradient>
  4505. <linearGradient id="linearColors8" x1="152" y1="130" x2="230" y2="190" gradientUnits="userSpaceOnUse">
  4506. <stop offset="0.2" stop-color="#FFFFFF"></stop>
  4507. <stop offset="1" stop-color="#00FF00"></stop>
  4508. </linearGradient>
  4509. <linearGradient id="linearColors9" x1="152" y1="130" x2="70" y2="190" gradientUnits="userSpaceOnUse">
  4510. <stop offset="0.2" stop-color="#FFFFFF"></stop>
  4511. <stop offset="1" stop-color="#0000FF"></stop>
  4512. </linearGradient>
  4513. <marker id="markerArrow" markerWidth="13" markerHeight="13" refX="2" refY="6" orient="auto">
  4514. <path d="M2,2 L2,11 L10,6 L2,2" style="fill:grey;" />
  4515. </marker>
  4516. <path d="M150 10 a120 120 0 0 1 103.9230 60" fill="none" stroke="url(#linearColors1)" stroke-width="20" />
  4517. <path d="M253.9230 70 a120 120 0 0 1 0 120" fill="none" stroke="url(#linearColors2)" stroke-width="20" />
  4518. <path d="M253.9230 190 a120 120 0 0 1 -103.9230 60" fill="none" stroke="url(#linearColors3)" stroke-width="20" />
  4519. <path d="M150 250 a120 120 0 0 1 -103.9230 -60" fill="none" stroke="url(#linearColors4)" stroke-width="20" />
  4520. <path d="M46.077 190 a120 120 0 0 1 0 -120" fill="none" stroke="url(#linearColors5)" stroke-width="20" />
  4521. <path d="M46.077 70 a120 120 0 0 1 103.9230 -60" fill="none" stroke="url(#linearColors6)" stroke-width="20" />
  4522. <path d="M150,50 C250,50 250,180 180,200" fill="none" stroke="grey" stroke-width="2" marker-end="url(#markerArrow)" />
  4523. <text class="Label" x="126" y="208">HUE</text>
  4524. <line x1="152" y1="130" x2="152" y2="35" stroke="url(#linearColors7)" stroke-width="4" />
  4525. <line x1="136" y1="120" x2="136" y2="45" stroke="grey" stroke-width="2" marker-end="url(#markerArrow)" />
  4526. <text class="Label" x="96" y="96">SAT</text>
  4527. <line x1="152" y1="130" x2="230" y2="190" stroke="url(#linearColors8)" stroke-width="4" />
  4528. <line x1="152" y1="130" x2="70" y2="190" stroke="url(#linearColors9)" stroke-width="4" />
  4529. <text x="120" y="-10">0° (Rot)</text>
  4530. <text x="270" y="60">60° (Gelb)</text>
  4531. <text x="270" y="220">120° (Grün)</text>
  4532. <text x="110" y="285">180° (Cyan)</text>
  4533. <text x="-60" y="220">240° (Blau)</text>
  4534. <text x="-90" y="60">300° (Magenta)</text>
  4535. </svg>
  4536. </a>
  4537. </td>
  4538. </tr>
  4539. </table>
  4540. </p>
  4541. <p><b>Farbangaben: HSV gegenüber RGB</b><p>
  4542. <p>
  4543. Im Normalfall kann eine Farbe im HSV Farbraum genauso wie im RGB Farbraum dargestellt werden.
  4544. <p>
  4545. Farben im HSV Farbraum wirken meist verständlicher.
  4546. Um ein Grün im HSV Farbraum etwas mehr in Richtung CYAN zu bewegen wird einfach der HUE Wert (Winkel) etwas erhöht.
  4547. Im RGB Farbraum ist die gleiche Aufgabe weniger intuitiv durch eine Erhöhung von BLAU zu erreichen.
  4548. <p>
  4549. Unterschiede werden jedoch bei Transitions deutlich.
  4550. Um BLAU langsam auf zu dimmen lauten die HSV Transitions 240,100,0 -> 240,100,100.
  4551. Um von ROT (Helligkeit 0) langsam auf BLAU zu dimmen wird im HSV Farbraum 0,100,0 -> 240,100,100 verwendet.
  4552. Im RGB Farbraum (#000000 -> #0000FF) kann nicht zwischen den beiden Varianten unterschieden werden.
  4553. Hier würde (richtiger weise, vermutlich jedoch anders als beabsichtigt) in beiden Fällen ein Weiß (Helligkeit 0) als Startwert erscheinen.
  4554. </p>
  4555. <p><b>Define</b></p>
  4556. <ul>
  4557. <li>
  4558. <p><code>define &lt;name&gt; WifiLight &lt;Leuchtmitteltyp&gt; &lt;bridgetyp&gt;:&lt;IP|FQDN&gt;</code></p>
  4559. <p>
  4560. <i><u>Beispiele</u></i>
  4561. <ul>
  4562. <p>
  4563. <i>definiert einen milight RGBW2 Leuchtmittel (Bulb oder LED stripe controller) an einer milight bridge Version 3 oder 4.
  4564. Die LED wird den maximal 4 verf&uuml;gbaren Gruppen pro bridge in der Reihenfolge der Definition zugeordnet:</i>
  4565. <br/>
  4566. <code>define wz.licht.decke WifiLight RGBW2 bridge-V3:192.168.178.142</code>
  4567. </ul>
  4568. <ul>
  4569. <p>
  4570. <i>definiert einen LD382A Controller mit RGBW Stripe:</i>
  4571. <br/>
  4572. <code>define wz.licht.decke WifiLight RGBW LD382A:192.168.178.142</code>
  4573. </ul>
  4574. <ul>
  4575. <p>
  4576. <i>definiert einen LD382A Controller mit RGB Stripe:</i>
  4577. <br/>
  4578. <code>define wz.licht.decke WifiLight RGB LD382A:192.168.178.142</code>
  4579. </ul>
  4580. <p>WifiLight verfügt über eine <a href="#WifiLight_Farbkalibrierung">"Farbkalibrierung"</a>. Sinnvollerweise sollte nach einem Leuchtmitteltausch oder einem define eine Kalibrierung vorgenommen werden.</p>
  4581. </ul>
  4582. </li>
  4583. <p><b>Set</b></p>
  4584. <ul>
  4585. <li>
  4586. <p><code>set &lt;name&gt; <b>on</b> [ramp]</code></p>
  4587. <p>Schaltet das device ein. Dabei wird entweder 100% Weiß oder die im Attribut "defaultColor" definierte Farbe gewählt.
  4588. <p>Erweiterte Parameter:
  4589. <ul>
  4590. <li>ramp</li>
  4591. </ul>
  4592. </p>
  4593. </li>
  4594. <li>
  4595. <p><code>set &lt;name&gt; <b>off</b> [ramp]</code></p>
  4596. <p>Schaltet das device aus.
  4597. <p>Erweiterte Parameter:
  4598. <ul>
  4599. <li>ramp</li>
  4600. </ul>
  4601. </p>
  4602. </li>
  4603. <li>
  4604. <p><code>set &lt;name&gt; <b>dimup</b></code></p>
  4605. <p>Erhöht die Helligkeit um einen festen Betrag. Dabei wird der im Attribut "dimStep" definierte Wert oder der Default "7" angewendet.<br>Dieser Befehl eignet sich besonders um die Helligkeit über einen Wandschalter oder eine Fernbedienung zu erhöhen.
  4606. <p>Erweiterte Parameter:
  4607. <ul>
  4608. <li>keine</li>
  4609. </ul>
  4610. </p>
  4611. </li>
  4612. <li>
  4613. <p><code>set &lt;name&gt; <b>dimdown</b></code></p>
  4614. <p>Verringert die Helligkeit um einen festen Betrag. Dabei wird der im Attribut "dimStep" definierte Wert oder der Default "7" angewendet.<br>Dieser Befehl eignet sich besonders um die Helligkeit über einen Wandschalter oder eine Fernbedienung zu verringern
  4615. <p>Erweiterte Parameter:
  4616. <ul>
  4617. <li>keine</li>
  4618. </ul>
  4619. </p>
  4620. </li>
  4621. <li>
  4622. <p><code>set &lt;name&gt; <b>dim</b> level [ramp] [q]</code></p>
  4623. <p>Setzt die Helligkeit auf den angegebenen level (0..100).<br>Dieser Befehl behält außerdem die eingestellte Farbe auch bei "dim 0" (ausgeschaltet) und nachfolgendem "dim xx" (eingeschaltet) bei. Daher stellt er eine alternative Form zu "off" / "on" dar. Letzteres würde immer die "defaultColor" wählen.
  4624. <p>Erweiterte Parameter:
  4625. <ul>
  4626. <li>ramp</li>
  4627. </ul>
  4628. </p>
  4629. <p>Flags:
  4630. <ul>
  4631. <li>q</li>
  4632. </ul>
  4633. </p>
  4634. </li>
  4635. <li>
  4636. <p><code>set &lt;name&gt; <b>HSV</b> H,S,V [ramp] [s|l|q] [event]</code></p>
  4637. <p>Setzt die Farbe im <a href="#WifiLight_Farbraum_HSV">HSV Farbraum</a>. Wenn die ramp (als Zeit in Sekunden) angegeben ist, berechnet das modul einen weichen Farbübergang von der aktuellen Farbe zur neu gesetzten.
  4638. <ul><i>Beispiel, setzt ein gesättigtes Blau mit halber Helligkeit:</i><br /><code>set wz.licht.decke HSV 240,100,50</code></ul>
  4639. <p>Erweiterte Parameter:
  4640. <ul>
  4641. <li>ramp</li>
  4642. </ul>
  4643. </p>
  4644. <p>Flags:
  4645. <ul>
  4646. <li>s l q event</li>
  4647. </ul>
  4648. </p>
  4649. </li>
  4650. <li>
  4651. <p><code>set &lt;name&gt; <b>RGB</b> RRGGBB [ramp] [l|s|q] [event]</code></p>
  4652. <p>Setzt die Farbe im RGB Farbraum.
  4653. <p>Erweiterte Parameter:
  4654. <ul>
  4655. <li>ramp</li>
  4656. </ul>
  4657. </p>
  4658. <p>Flags:
  4659. <ul>
  4660. <li>s l q event</li>
  4661. </ul>
  4662. </p>
  4663. </ul>
  4664. </li>
  4665. <p><b>Bedeutung der Flags</b></p>
  4666. Bestimmte Befehle (set) können mit speziellen Flags versehen werden.
  4667. <p>
  4668. <ul>
  4669. <li>ramp:
  4670. <ul>
  4671. Zeit in Sekunden für einen weichen Farb- oder Helligkeitsübergang. Der weiche Übergang startet bei der aktuell sichtbaren Farbe und wird zur angegeben berechnet.
  4672. </ul>
  4673. </li>
  4674. <li>s:
  4675. <ul>
  4676. (short, default). Ein weicher Übergang zu einer anderen Farbe wird im <a href="#WifiLight_Farbkreis">"Farbkreis"</a> auf dem kürzesten Weg durchgeführt.</br>
  4677. Eine Transition von ROT nach GRÜN führt auf dem kürzesten Weg über GELB.
  4678. </ul>
  4679. </li>
  4680. <li>l:
  4681. <ul>
  4682. (long). Ein weicher Übergang zu einer anderen Farbe wird im <a href="#WifiLight_Farbkreis">"Farbkreis"</a> auf dem "langen" Weg durchgeführt.</br>
  4683. Eine Transition von ROT nach GRÜN führt dann über MAGENTA, BLAU, und CYAN.
  4684. </ul>
  4685. </li>
  4686. <li>q:
  4687. <ul>
  4688. (queue). Kommandos mit diesem Flag werden in einer internen Warteschlange zwischengespeichert und erst ausgeführt nachdem die aktuell laufenden weichen Übergänge
  4689. abgearbeitet wurden. Kommandos ohne das Flag werden sofort abgearbeitet. Dabei werden alle laufenden Übergänge sofort abgebrochen und die Warteschlange wird gelöscht.
  4690. </ul>
  4691. </li>
  4692. <li>event:
  4693. <ul>
  4694. Beliebige Bezeichnung ([A-Za-z_0-9])
  4695. <p>
  4696. WifiLight erzeugt bei Verwendung dieses Flags im Verlauf weicher Übergange zu einer anderen Farbe Nachrichten (events) in der Form:
  4697. <p>
  4698. <code>WifiLight &ltNAME&gt programm: &ltEVENT&gt &ltXX&gt</code>.
  4699. <p>
  4700. &ltEVENT&gt entspricht dem Namen so wie im Flag angegeben.<br/>
  4701. &ltXX&gt ist der prozentuale Fortschritt des Übergangs.<br/>
  4702. <p>
  4703. Je nach Gesamtdauer des Übergangs werden die Werte von 0 bis 100 nicht komplett durchlaufen wobei jedoch für 0% und 100% immer ein event garantiert ist. Auf diese events kann dann innerhalb von notify oder DOIF reagiert werden um zum Beispiel:
  4704. <ul>
  4705. <li>die Lautstärke eines Radios anzupassen wenn eine LED morgens langsam hochgedimmt wird</li>
  4706. <li>ein Farbübergang kann in einem notify neu gestartet werden wenn er komplett ist (loop)</li>
  4707. <li>andere Leuchtmittel können mit erstellten Farbübergängen synchronisiert werden</li>
  4708. </ul>
  4709. </ul>
  4710. </li>
  4711. </ul>
  4712. <p><b><a name="WifiLight_Farbkalibrierung"></a>Farbkalibrierung</b></p>
  4713. WifiLight unterstützt zwei unterschiedliche Formen der Farbkalibrierungen:
  4714. <ul>
  4715. <p>
  4716. <b>Korrektur gesättigter Farben</b>
  4717. <p>
  4718. Hintergrund:
  4719. <p>
  4720. GELB, zum Beispiel, ist definiert als Mischung aus ROTEM und GRÜNEM Licht zu gleichen Teilen.
  4721. Je nach verwendeter LED und Ansteuerung ist der GRÜNE Kanal nun möglicherweise viel leuchtstärker.
  4722. Wenn jetzt also die ROTE und GRÜNE LED jeweils voll angesteuert werden überwiegt GRÜN in dieser Mischung und das gewünschte GELB bekäme einen deutlichen Grünstich.
  4723. In diesem Beispiel würde jetzt für HSV 60,100,100 kein Gelb (entsprechend 60° im <a href="#WifiLight_Farbkreis">"Farbkreis"</a>) erzeugt.
  4724. Stattdessen würde GRÜN mit GELBSTICH erzeugt das vielleicht einem geschätzten Farbwinkel von 80° entspricht.
  4725. Die erforderliche Korrektur für GELB würde also minus 20° betragen (60° SOLL - 80° IST = -20° Korrektur).
  4726. GELB müsste als um -20° korrigiert werden. Mögliche Werte pro Korrektur-Punkt sind +/- 29°.
  4727. <p>
  4728. Vorgehen:
  4729. <p>
  4730. Die Korrektur der Vollfarben wird über das Attribut "colorCast" gesteuert. Dabei werden 6 (Komma getrennte) Werte im Bereich -29 bis 29 angegeben.
  4731. Diese Werte stehen entsprechen der Winkelkorrektur für ROT (0°), GELB (60°), GRÜN (120°), CYAN (180°), BLAU (240°) und MAGENTA (300°).
  4732. Zuerst sollte die Abweichung für 60°/180°/300° (die Mischfarben) so wie in obigem Beispiel ermittelt und im Attribut hinterlegt werden.
  4733. Im Anschluss sollten die Primärfarben (0°/120°/240°) so korrigiert werden das die weichen Übergänge zwischen benachbarten reinen Farben möglichst linear erscheinen.
  4734. Dieser Vorgang muss eventuell iterativ mehrfach wiederholt werden bis das Ergebniss stimmig ist.
  4735. <p>
  4736. <b>Weißabgleich</b>
  4737. <p>
  4738. Hintergrund:
  4739. <p>
  4740. Einige Leuchtmittel erzeugen weißes Licht durch Mischung der RGB Kanäle (zum Beispiel LW12).
  4741. Je nach Leuchtstärke der RGB Kanäle der verwendeten LED Streifen unterscheidet sich das Ergebnis und eine oder zwei Farben dominieren.
  4742. Zusätzlich gibt es verschiedene Formen weißen Lichtes. Kaltes Licht hat einen höheren Blauanteil.
  4743. Dagegen wird in Mitteleuropa für Leuchtmittel meist warm-weiß verwendet welches einen hohen ROT- und geringen BLAU Anteil hat.
  4744. <p>
  4745. WifiLight bietet die Möglichkeit bei RGB gemischtem Weiß die Zusammensetzung anzupassen. Die Anpassung erfolgt über das Attribut "whitePoint".
  4746. Dieses erwartet für jeden der drei RGB Kanäle einen Wert zwischen 0 und 1 (ein Komma wird als Punkt angegeben). Die drei Werte werden mit einem normalen Komma getrennt.
  4747. <p>
  4748. Vorgehen:
  4749. <p>
  4750. Eine Angabe von "1,1,1" setzt alle die drei Kanäle auf jeweils 100%. Angenommen der BLAU Anteil des weißen Lichtes soll nun verringert werden.
  4751. Ein Wert von "1,1,0.5" setzt den dritten Kanal (BLAU) bei Weiß auf 0.5 entsprechend 50%. Vor einem Weißabgleich sollte die Korrektur der Vollfarben abgeschlossen sein.
  4752. </ul>
  4753. <p><b>Attribute</b></p>
  4754. <ul>
  4755. <li>
  4756. <code>attr &ltname&gt <b>colorCast</b> &ltR,Y,G,C,B,M&gt</code>
  4757. <p>
  4758. <a href="#WifiLight_Farbkalibrierung">Farbkalibrierung</a> der voll gesättigten Farben.
  4759. R(ed), Y(ellow), G(reen), C(yan), B(lue), M(agenta) im Bereich +/- 29
  4760. </li>
  4761. <li>
  4762. <code>attr &ltname&gt <b>defaultColor</b> &ltH,S,V&gt</code>
  4763. <p>
  4764. HSV Angabe der Lichtfarbe die bei "on" gewählt wird. Default ist Weiß.
  4765. </li>
  4766. <li>
  4767. <code>attr &ltname&gt <b>defaultRamp</b> &lt0 bis X&gt</code>
  4768. <p>
  4769. Zeit in Sekunden. Wenn dieses Attribut gesetzt ist wird implizit immer ein weicher Übergang erzeugt wenn keine Ramp im set angegeben ist.
  4770. </li>
  4771. <li>
  4772. <code>attr &ltname&gt <b>dimStep</b> &lt0 bis 100&gt</code>
  4773. <p>
  4774. Wert um den die Helligkeit bei dimUp und dimDown verändert wird. Default 7.
  4775. </li>
  4776. <li>
  4777. <code>attr &ltname&gt <b>gamma</b> &ltX.X&gt</code>
  4778. <p>
  4779. Das menschliche Auge nimmt Helligkeitsänderungen sehr unterschiedlich wahr (logarithmisch).
  4780. Bei geringer Ausgangshelligkeit wird schon eine kleine Helligkeitsänderung als sehr stark empfunden und auf der anderen Seite sind bei großer Helligkeit starke Änderungen notwendig.
  4781. Daher ist eine logarithmische Korrektur des Helligkeitsanstiegs der Leuchtmittel erforderlich damit der Anstieg als gleichmäßig empfunden wird.
  4782. Einige controller führen diese Korrektur intern durch. In anderen Fällen ist es notwendig diese Korrektur im Modul zu hinterlegen.
  4783. Ein gamma Wert von 1.0 (default) führt zu einer linearen Ausgabe der Werte. Werte kleiner als 1.0 führen zu einer logarithmischem Korrektur.
  4784. </li>
  4785. <li>
  4786. <code>attr &ltname&gt <b>whitePoint</b> &ltR,G,B&gt</code>
  4787. <p>
  4788. <a href="#WifiLight_Farbkalibrierung">Farbkalibrierung</a> für RGB gemischtes weißes Licht.
  4789. </li>
  4790. <li>
  4791. <code>attr &ltname&gt <b><a href="#readingFnAttributes">readingFnAttributes</a></b></code>
  4792. </li>
  4793. </ul>
  4794. <p><b>Farbiges Icon für FhemWeb</b>
  4795. <ul>
  4796. <p>
  4797. Um ein farbiges Icon für <a href="#FHEMWEB">FhemWeb</a> zu aktivieren muss das folgende Attribut gesetzt sein:
  4798. <p>
  4799. <li>
  4800. <code>attr &ltname&gt <b>devStateIcon</b> {Color_devStateIcon(ReadingsVal($name,"RGB","000000"))}</code>
  4801. </li>
  4802. </ul>
  4803. <p><b>Colorpicker für FhemWeb</b>
  4804. <ul>
  4805. <p>
  4806. Um den Color-Picker für <a href="#FHEMWEB">FhemWeb</a> zu aktivieren müssen folgende Attribute gesetzt werden:
  4807. <p>
  4808. <li>
  4809. <code>attr &ltname&gt <b>webCmd</b> RGB</code>
  4810. </li>
  4811. <li>
  4812. <code>attr &ltname&gt <b>widgetOverride</b> RGB:colorpicker,RGB</code>
  4813. </li>
  4814. </ul>
  4815. </ul>
  4816. =end html_DE