32_WifiLight.pm 204 KB

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