00_SIGNALduino.pm 182 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483
  1. ##############################################
  2. # $Id: 00_SIGNALduino.pm 16624 2018-04-15 18:58:49Z rudolfkoenig $
  3. #
  4. # v3.3.2 (stable release 3.3)
  5. # The module is inspired by the FHEMduino project and modified in serval ways for processing the incomming messages
  6. # see http://www.fhemwiki.de/wiki/SIGNALDuino
  7. # It was modified also to provide support for raw message handling which can be send from the SIGNALduino
  8. # The purpos is to use it as addition to the SIGNALduino which runs on an arduno nano or arduino uno.
  9. # It routes Messages serval Modules which are already integrated in FHEM. But there are also modules which comes with it.
  10. # N. Butzek, S. Butzek, 2014-2015
  11. # S.Butzek,Ralf9 2016-2018
  12. package main;
  13. use strict;
  14. use warnings;
  15. use Time::HiRes qw(gettimeofday);
  16. use Data::Dumper qw(Dumper);
  17. use Scalar::Util qw(looks_like_number);
  18. no warnings 'portable';
  19. #$| = 1; #Puffern abschalten, Hilfreich für PEARL WARNINGS Search
  20. #use POSIX qw( floor); # can be removed
  21. #use Math::Round qw();
  22. use constant {
  23. SDUINO_VERSION => "v3.3.2",
  24. SDUINO_INIT_WAIT_XQ => 1.5, # wait disable device
  25. SDUINO_INIT_WAIT => 2,
  26. SDUINO_INIT_MAXRETRY => 3,
  27. SDUINO_CMD_TIMEOUT => 10,
  28. SDUINO_KEEPALIVE_TIMEOUT => 60,
  29. SDUINO_KEEPALIVE_MAXRETRY => 3,
  30. SDUINO_WRITEQUEUE_NEXT => 0.3,
  31. SDUINO_WRITEQUEUE_TIMEOUT => 2,
  32. SDUINO_DISPATCH_VERBOSE => 5, # default 5
  33. };
  34. sub SIGNALduino_Attr(@);
  35. #sub SIGNALduino_Clear($); # wird nicht mehr benoetigt
  36. sub SIGNALduino_HandleWriteQueue($);
  37. sub SIGNALduino_Parse($$$$@);
  38. sub SIGNALduino_Read($);
  39. #sub SIGNALduino_ReadAnswer($$$$); # wird nicht mehr benoetigt
  40. sub SIGNALduino_Ready($);
  41. sub SIGNALduino_Write($$$);
  42. sub SIGNALduino_SimpleWrite(@);
  43. sub SIGNALduino_Log3($$$);
  44. #my $debug=0;
  45. my %gets = ( # Name, Data to send to the SIGNALduino, Regexp for the answer
  46. "version" => ["V", 'V\s.*SIGNAL(duino|ESP).*'],
  47. "freeram" => ["R", '^[0-9]+'],
  48. "raw" => ["", '.*'],
  49. "uptime" => ["t", '^[0-9]+' ],
  50. "cmds" => ["?", '.*Use one of[ 0-9A-Za-z]+[\r\n]*$' ],
  51. # "ITParms" => ["ip",'.*'],
  52. "ping" => ["P",'^OK$'],
  53. "config" => ["CG",'^MS.*MU.*MC.*'],
  54. "protocolIDs" => ["none",'none'],
  55. "ccconf" => ["C0DnF", 'C0Dn11.*'],
  56. "ccreg" => ["C", '^C.* = .*'],
  57. "ccpatable" => ["C3E", '^C3E = .*'],
  58. # "ITClock" => ["ic", '\d+'],
  59. # "FAParms" => ["fp", '.*' ],
  60. # "TCParms" => ["dp", '.*' ],
  61. # "HXParms" => ["hp", '.*' ]
  62. );
  63. my %sets = (
  64. "raw" => '',
  65. "flash" => '',
  66. "reset" => 'noArg',
  67. "close" => 'noArg',
  68. #"disablereceiver" => "",
  69. #"ITClock" => 'slider,100,20,700',
  70. "enableMessagetype" => 'syncedMS,unsyncedMU,manchesterMC',
  71. "disableMessagetype" => 'syncedMS,unsyncedMU,manchesterMC',
  72. "sendMsg" => "",
  73. "cc1101_freq" => '',
  74. "cc1101_bWidth" => '',
  75. "cc1101_rAmpl" => '',
  76. "cc1101_sens" => '',
  77. "cc1101_patable_433" => '-10_dBm,-5_dBm,0_dBm,5_dBm,7_dBm,10_dBm',
  78. "cc1101_patable_868" => '-10_dBm,-5_dBm,0_dBm,5_dBm,7_dBm,10_dBm',
  79. );
  80. my %patable = (
  81. "433" =>
  82. {
  83. "-10_dBm" => '34',
  84. "-5_dBm" => '68',
  85. "0_dBm" => '60',
  86. "5_dBm" => '84',
  87. "7_dBm" => 'C8',
  88. "10_dBm" => 'C0',
  89. },
  90. "868" =>
  91. {
  92. "-10_dBm" => '27',
  93. "-5_dBm" => '67',
  94. "0_dBm" => '50',
  95. "5_dBm" => '81',
  96. "7_dBm" => 'CB',
  97. "10_dBm" => 'C2',
  98. },
  99. );
  100. my @ampllist = (24, 27, 30, 33, 36, 38, 40, 42); # rAmpl(dB)
  101. ## Supported Clients per default
  102. my $clientsSIGNALduino = ":IT:"
  103. ."CUL_TCM97001:"
  104. ."SD_RSL:"
  105. ."OREGON:"
  106. ."CUL_TX:"
  107. ."SD_AS:"
  108. ."Hideki:"
  109. ."SD_WS07:"
  110. ."SD_WS09:"
  111. ." :" # Zeilenumbruch
  112. ."SD_WS:"
  113. ."RFXX10REC:"
  114. ."Dooya:"
  115. ."SOMFY:"
  116. ."SD_UT:" ## BELL 201.2 TXA
  117. ."SD_WS_Maverick:"
  118. ."FLAMINGO:"
  119. ."CUL_WS:"
  120. ."Revolt:"
  121. ." :" # Zeilenumbruch
  122. ."FS10:"
  123. ."CUL_FHTTK:"
  124. ."Siro:"
  125. ."FHT:"
  126. ."FS20:"
  127. ."SIGNALduino_un:"
  128. ;
  129. ## default regex match List for dispatching message to logical modules, can be updated during runtime because it is referenced
  130. my %matchListSIGNALduino = (
  131. "1:IT" => "^i......", # Intertechno Format
  132. "2:CUL_TCM97001" => "^s[A-Fa-f0-9]+", # Any hex string beginning with s
  133. "3:SD_RSL" => "^P1#[A-Fa-f0-9]{8}",
  134. "5:CUL_TX" => "^TX..........", # Need TX to avoid FHTTK
  135. "6:SD_AS" => "^P2#[A-Fa-f0-9]{7,8}", # Arduino based Sensors, should not be default
  136. "4:OREGON" => "^(3[8-9A-F]|[4-6][0-9A-F]|7[0-8]).*",
  137. "7:Hideki" => "^P12#75[A-F0-9]+",
  138. "9:CUL_FHTTK" => "^T[A-F0-9]{8}",
  139. "10:SD_WS07" => "^P7#[A-Fa-f0-9]{6}F[A-Fa-f0-9]{2}(#R[A-F0-9][A-F0-9]){0,1}\$",
  140. "11:SD_WS09" => "^P9#F[A-Fa-f0-9]+",
  141. "12:SD_WS" => '^W\d+x{0,1}#.*',
  142. "13:RFXX10REC" => '^(20|29)[A-Fa-f0-9]+',
  143. "14:Dooya" => '^P16#[A-Fa-f0-9]+',
  144. "15:SOMFY" => '^Ys[0-9A-F]+',
  145. "16:SD_WS_Maverick" => '^P47#[A-Fa-f0-9]+',
  146. "17:SD_UT" => '^u30#.*', ## BELL 201.2 TXA
  147. "18:FLAMINGO" => '^P13#[A-Fa-f0-9]+', ## Flamingo Smoke
  148. "19:CUL_WS" => '^K[A-Fa-f0-9]{5,}',
  149. "20:Revolt" => '^r[A-Fa-f0-9]{22}',
  150. "21:FS10" => '^P61#[A-F0-9]+',
  151. "22:Siro" => '^P72#[A-Fa-f0-9]+',
  152. "23:FHT" => "^81..(04|09|0d)..(0909a001|83098301|c409c401)..",
  153. "24:FS20" => "^81..(04|0c)..0101a001",
  154. "X:SIGNALduino_un" => '^[u]\d+#.*',
  155. );
  156. my %ProtocolListSIGNALduino = (
  157. "0" =>
  158. {
  159. name => 'weather1', # Logilink, NC, WS, TCM97001 etc.
  160. comment => 'Logilink, NC, WS, TCM97001 etc',
  161. id => '0',
  162. one => [1,-8],
  163. zero => [1,-4],
  164. sync => [1,-18],
  165. clockabs => '500', # not used now
  166. format => 'twostate', # not used now
  167. preamble => 's', # prepend to converted message
  168. postamble => '00', # Append to converted message
  169. clientmodule => 'CUL_TCM97001', # not used now
  170. #modulematch => '^s[A-Fa-f0-9]+', # not used now
  171. length_min => '24',
  172. length_max => '46',
  173. paddingbits => '8', # pad up to 8 bits, default is 4
  174. },
  175. "1" =>
  176. {
  177. name => 'ConradRSL', #
  178. id => '1',
  179. one => [2,-1],
  180. zero => [1,-2],
  181. sync => [1,-11],
  182. clockabs => '560', # not used now
  183. format => 'twostate', # not used now
  184. preamble => 'P1#', # prepend to converted message
  185. postamble => '', # Append to converted message
  186. clientmodule => 'SD_RSL', # not used now
  187. modulematch => '^P1#[A-Fa-f0-9]{8}', # not used now
  188. length_min => '20', # 23
  189. length_max => '40', # 24
  190. },
  191. "2" =>
  192. {
  193. name => 'AS, Self build arduino sensor',
  194. comment => 'developModule. SD_AS module is only in github available',
  195. developId => 'm',
  196. id => '2',
  197. one => [1,-2],
  198. zero => [1,-1],
  199. sync => [1,-20],
  200. clockabs => '500', # not used now
  201. format => 'twostate',
  202. preamble => 'P2#', # prepend to converted message
  203. clientmodule => 'SD_AS', # not used now
  204. modulematch => '^P2#.{7,8}',
  205. length_min => '32',
  206. length_max => '34', # Don't know maximal lenth of a valid message
  207. paddingbits => '8', # pad up to 8 bits, default is 4
  208. },
  209. "3" =>
  210. {
  211. name => 'itv1',
  212. id => '3',
  213. one => [3,-1],
  214. zero => [1,-3],
  215. #float => [-1,3], # not full supported now later use
  216. sync => [1,-31],
  217. clockabs => -1, # -1=auto
  218. format => 'twostate', # not used now
  219. preamble => 'i',
  220. clientmodule => 'IT', # not used now
  221. modulematch => '^i......', # not used now
  222. length_min => '24',
  223. #length_max => '800', # Don't know maximal lenth of a valid message
  224. },
  225. "3.1" =>
  226. {
  227. name => 'itv1_sync40',
  228. comment => 'IT remote Control PAR 1000',
  229. id => '3',
  230. one => [3,-1],
  231. zero => [1,-3],
  232. #float => [-1,3], # not full supported now later use
  233. sync => [1,-40],
  234. clockabs => -1, # -1=auto
  235. format => 'twostate', # not used now
  236. preamble => 'i',
  237. clientmodule => 'IT', # not used now
  238. modulematch => '^i......', # not used now
  239. length_min => '24',
  240. #length_max => '800', # Don't know maximal lenth of a valid message
  241. },
  242. "4" =>
  243. {
  244. name => 'arctech2',
  245. id => '4',
  246. #one => [1,-5,1,-1],
  247. #zero => [1,-1,1,-5],
  248. one => [1,-5],
  249. zero => [1,-1],
  250. #float => [-1,3], # not full supported now, for later use
  251. sync => [1,-14],
  252. clockabs => -1, # -1 = auto
  253. format => 'twostate', # tristate can't be migrated from bin into hex!
  254. preamble => 'i', # Append to converted message
  255. postamble => '00', # Append to converted message
  256. clientmodule => 'IT', # not used now
  257. modulematch => '^i......', # not used now
  258. length_min => '32',
  259. #length_max => '76', # Don't know maximal lenth of a valid message
  260. },
  261. "5" => ## Similar protocol as intertechno, but without sync
  262. {
  263. name => 'unitec6899',
  264. id => '5',
  265. one => [3,-1],
  266. zero => [1,-3],
  267. clockabs => 500, # -1 = auto
  268. format => 'twostate', # tristate can't be migrated from bin into hex!
  269. preamble => 'p5#', # Append to converted message
  270. clientmodule => 'IT', # not used now
  271. modulematch => '^i......', # not used now
  272. length_min => '24',
  273. },
  274. "6" => ## Eurochron Protocol
  275. {
  276. name => 'weatherID6',
  277. id => '6',
  278. one => [1,-10],
  279. zero => [1,-5],
  280. sync => [1,-36], # This special device has no sync
  281. clockabs => 220, # -1 = auto
  282. format => 'twostate', # tristate can't be migrated from bin into hex!
  283. preamble => 'u6#', # Append to converted message
  284. #clientmodule => '', # not used now
  285. #modulematch => '^u......', # not used now
  286. length_min => '24',
  287. },
  288. "7" => ## weather sensors like EAS800z
  289. {
  290. name => 'weatherID7',
  291. comment => 'EAS800z, FreeTec NC-7344',
  292. id => '7',
  293. one => [1,-4],
  294. zero => [1,-2],
  295. sync => [1,-8],
  296. clockabs => 484,
  297. format => 'twostate',
  298. preamble => 'P7#', # prepend to converted message
  299. clientmodule => 'SD_WS07', # not used now
  300. modulematch => '^P7#.{6}F.{2}', # not used now
  301. length_min => '35',
  302. length_max => '40',
  303. },
  304. "8" => ## TX3 (ITTX) Protocol
  305. {
  306. name => 'TX3 Protocol',
  307. id => '8',
  308. one => [1,-2],
  309. zero => [2,-2],
  310. #sync => [1,-8], #
  311. clockabs => 470, #
  312. format => 'pwm', #
  313. preamble => 'TX', # prepend to converted message
  314. clientmodule => 'CUL_TX', # not used now
  315. modulematch => '^TX......', # not used now
  316. length_min => '43',
  317. length_max => '44',
  318. remove_zero => 1, # Removes leading zeros from output
  319. },
  320. "9" => ## Funk Wetterstation CTW600
  321. {
  322. name => 'CTW 600',
  323. comment => 'FunkWS WH1080/WH3080/CTW600',
  324. id => '9',
  325. zero => [3,-2],
  326. one => [1,-2],
  327. #float => [-1,3], # not full supported now, for later use
  328. #sync => [1,-8], #
  329. clockabs => 480, # -1 = auto undef=noclock
  330. format => 'pwm', # tristate can't be migrated from bin into hex!
  331. preamble => 'P9#', # prepend to converted message
  332. clientmodule => 'SD_WS09', # not used now
  333. #modulematch => '^u9#.....', # not used now
  334. length_min => '60',
  335. length_max => '120',
  336. },
  337. "10" => ## Oregon Scientific 2
  338. {
  339. name => 'OSV2o3',
  340. id => '10',
  341. clockrange => [300,520], # min , max
  342. format => 'manchester', # tristate can't be migrated from bin into hex!
  343. clientmodule => 'OREGON',
  344. modulematch => '^(3[8-9A-F]|[4-6][0-9A-F]|7[0-8]).*',
  345. length_min => '64',
  346. length_max => '220',
  347. method => \&SIGNALduino_OSV2, # Call to process this message
  348. polarity => 'invert',
  349. },
  350. "11" => ## Arduino Sensor
  351. {
  352. name => 'AS',
  353. id => '11',
  354. clockrange => [380,425], # min , max
  355. format => 'manchester', # tristate can't be migrated from bin into hex!
  356. preamble => 'P2#', # prepend to converted message
  357. clientmodule => 'SD_AS', # not used now
  358. modulematch => '^P2#.{7,8}',
  359. length_min => '52',
  360. length_max => '56',
  361. method => \&SIGNALduino_AS # Call to process this message
  362. },
  363. "12" => ## Hideki
  364. {
  365. name => 'Hideki protocol',
  366. comment => 'Hideki messages are sometimes received as inverted (check in sub)',
  367. id => '12',
  368. clockrange => [420,510], # min, max better for Bresser Sensors, OK for hideki/Hideki/TFA too
  369. format => 'manchester',
  370. preamble => 'P12#', # prepend to converted message
  371. clientmodule => 'hideki', # not used now
  372. modulematch => '^P12#75.+', # not used now
  373. length_min => '71',
  374. length_max => '128',
  375. method => \&SIGNALduino_Hideki, # Call to process this message
  376. #polarity => 'invert',
  377. },
  378. "13" => ## FLAMINGO FA 21
  379. {
  380. name => 'FLAMINGO FA21',
  381. id => '13',
  382. one => [1,-2],
  383. zero => [1,-4],
  384. sync => [1,-20,10,-1],
  385. clockabs => 800,
  386. format => 'twostate',
  387. preamble => 'P13#', # prepend to converted message
  388. clientmodule => 'FLAMINGO', # not used now
  389. #modulematch => 'P13#.*', # not used now
  390. length_min => '24',
  391. length_max => '26',
  392. },
  393. "13.1" => ## FLAMINGO FA20
  394. {
  395. name => 'FLAMINGO FA21 b',
  396. id => '13',
  397. one => [1,-2],
  398. zero => [1,-4],
  399. start => [20,-1],
  400. clockabs => 800,
  401. format => 'twostate',
  402. preamble => 'P13#', # prepend to converted message
  403. clientmodule => 'FLAMINGO', # not used now
  404. #modulematch => 'P13#.*', # not used now
  405. length_min => '24',
  406. length_max => '24',
  407. },
  408. "14" => ## Heidemann HX
  409. {
  410. name => 'Heidemann HX',
  411. id => '14',
  412. one => [1,-2],
  413. zero => [1,-1],
  414. #float => [-1,3], # not full supported now, for later use
  415. sync => [1,-14], #
  416. clockabs => 350,
  417. format => 'twostate',
  418. preamble => 'u14#', # prepend to converted message
  419. #clientmodule => '', # not used now
  420. #modulematch => '', # not used now
  421. length_min => '10',
  422. length_max => '20',
  423. },
  424. "15" => ## TCM234759
  425. {
  426. name => 'TCM Bell',
  427. id => '15',
  428. one => [1,-1],
  429. zero => [1,-2],
  430. sync => [1,-45], #
  431. clockabs => 700,
  432. format => 'twostate',
  433. preamble => 'u15#', # prepend to converted message
  434. #clientmodule => '', # not used now
  435. #modulematch => '', # not used now
  436. length_min => '10',
  437. length_max => '20',
  438. #method => \&SIGNALduino_Cresta # Call to process this message
  439. },
  440. "16" => # Rohrmotor24 und andere Funk Rolladen / Markisen Motoren
  441. {
  442. name => 'Dooya shutter',
  443. id => '16',
  444. one => [2,-1],
  445. zero => [1,-3],
  446. start => [17,-5],
  447. clockabs => 280,
  448. format => 'twostate',
  449. preamble => 'P16#', # prepend to converted message
  450. clientmodule => 'Dooya', # not used now
  451. #modulematch => '', # not used now
  452. length_min => '39',
  453. length_max => '40',
  454. },
  455. "17" =>
  456. {
  457. name => 'arctech',
  458. id => '17',
  459. one => [1,-5,1,-1],
  460. zero => [1,-1,1,-5],
  461. #one => [1,-5],
  462. #zero => [1,-1],
  463. sync => [1,-10],
  464. float => [1,-1,1,-1],
  465. clockabs => -1, # -1 = auto
  466. format => 'twostate', # tristate can't be migrated from bin into hex!
  467. preamble => 'i', # Append to converted message
  468. postamble => '00', # Append to converted message
  469. clientmodule => 'IT', # not used now
  470. modulematch => '^i......', # not used now
  471. length_min => '32',
  472. #length_max => '76', # Don't know maximal lenth of a valid message
  473. postDemodulation => \&SIGNALduino_bit2Arctec,
  474. },
  475. "18" => ## Oregon Scientific v1
  476. {
  477. name => 'OSV1',
  478. id => '18',
  479. clockrange => [1400,1500], # min , max
  480. format => 'manchester', # tristate can't be migrated from bin into hex!
  481. preamble => '',
  482. clientmodule => 'OREGON',
  483. modulematch => '^[0-9A-F].*',
  484. length_min => '31',
  485. length_max => '32',
  486. polarity => 'invert', # invert bits
  487. method => \&SIGNALduino_OSV1 # Call to process this message
  488. },
  489. #"19" => # nothing knowing about this 2015-09-28 01:25:40-MS;P0=-8916;P1=-19904;P2=390;P3=-535;P4=-1020;P5=12846;P6=1371;D=2120232323232324242423232323232323232320239;CP=2;SP=1;
  490. #
  491. # {
  492. # name => 'unknown19',
  493. # id => '19',
  494. # one => [1,-2],
  495. # zero => [1,-1],
  496. # sync => [1,-50,1,-22],
  497. # clockabs => 395,
  498. # format => 'twostate',
  499. # preamble => 'u19#', # prepend to converted message
  500. # #clientmodule => '', # not used now
  501. # #modulematch => '', # not used now
  502. # length_min => '16',
  503. # length_max => '32',
  504. # },
  505. "20" => #Livolo
  506. {
  507. name => 'livolo',
  508. id => '20',
  509. one => [3],
  510. zero => [1],
  511. start => [5],
  512. clockabs => 110, #can be 90-140
  513. format => 'twostate',
  514. preamble => 'u20#', # prepend to converted message
  515. #clientmodule => '', # not used now
  516. #modulematch => '', # not used now
  517. length_min => '16',
  518. filterfunc => 'SIGNALduino_filterSign',
  519. },
  520. "21" => #Einhell Garagentor
  521. {
  522. name => 'einhell garagedoor',
  523. id => '21',
  524. one => [-3,1],
  525. zero => [-1,3],
  526. #sync => [-50,1],
  527. start => [-50,1],
  528. clockabs => 400, #ca 400us
  529. format => 'twostate',
  530. preamble => 'u21#', # prepend to converted message
  531. #clientmodule => '', # not used now
  532. #modulematch => '', # not used now
  533. length_min => '32',
  534. length_max => '32',
  535. paddingbits => '1', # This will disable padding
  536. },
  537. "22" => #TX-EZ6 / Meteo
  538. {
  539. name => 'TX-EZ6',
  540. id => '22',
  541. one => [1,-8],
  542. zero => [1,-3],
  543. sync => [1,16],
  544. clockabs => 500, #ca 400us
  545. format => 'twostate',
  546. preamble => 'u22#', # prepend to converted message
  547. #clientmodule => '', # not used now
  548. #modulematch => '', # not used now
  549. length_min => '40',
  550. #length_max => '', # must be tested
  551. },
  552. "23" => # Pearl Sensor
  553. {
  554. name => 'perl unknown',
  555. id => '23',
  556. one => [1,-6],
  557. zero => [1,-1],
  558. sync => [1,-50],
  559. clockabs => 200, #ca 200us
  560. format => 'twostate',
  561. preamble => 'u23#', # prepend to converted message
  562. #clientmodule => '', # not used now
  563. #modulematch => '', # not used now
  564. length_min => '36',
  565. length_max => '44',
  566. },
  567. "24" => # visivon
  568. {
  569. name => 'visivon remote',
  570. id => '24',
  571. one => [3,-2],
  572. zero => [1,-5],
  573. #one => [3,-2],
  574. #zero => [1,-1],
  575. start => [30,-5],
  576. clockabs => 150, #ca 150us
  577. format => 'twostate',
  578. preamble => 'u24#', # prepend to converted message
  579. #clientmodule => '', # not used now
  580. #modulematch => '', # not used now
  581. length_min => '54',
  582. length_max => '58',
  583. },
  584. "25" => # LES remote for led lamp
  585. {
  586. name => 'les led remote',
  587. id => '25',
  588. one => [-2,1],
  589. zero => [-1,2],
  590. sync => [-46,1], # this is a end marker, but we use this as a start marker
  591. clockabs => 350, #ca 350us
  592. format => 'twostate',
  593. preamble => 'u25#', # prepend to converted message
  594. #clientmodule => '', # not used now
  595. #modulematch => '', # not used now
  596. length_min => '24',
  597. length_max => '50', # message has only 24 bit, but we get more than one message, calculation has to be corrected
  598. },
  599. "26" => # some remote code send by flamingo style remote controls
  600. {
  601. name => 'remote26',
  602. id => '26',
  603. one => [1,-3],
  604. zero => [3,-1],
  605. # sync => [1,-6], # Message is not provided as MS, due to small fact
  606. start => [1,-6], # Message is not provided as MS, due to small fact
  607. clockabs => 380, #ca 380
  608. format => 'twostate',
  609. preamble => 'u26#', # prepend to converted message
  610. #clientmodule => '', # not used now
  611. #modulematch => '', # not used now
  612. length_min => '24',
  613. length_max => '24', # message has only 24 bit, but we get more than one message, calculation has to be corrected
  614. },
  615. "27" => # some remote code, send by flamingo style remote controls
  616. {
  617. name => 'remote27',
  618. id => '27',
  619. one => [1,-2],
  620. zero => [2,-1],
  621. start => [6,-15], # Message is not provided as MS, worakround is start
  622. clockabs => 480, #ca 480
  623. format => 'twostate',
  624. preamble => 'u27#', # prepend to converted message
  625. #clientmodule => '', # not used now
  626. #modulematch => '', # not used now
  627. length_min => '24',
  628. length_max => '24',
  629. },
  630. "28" => # some remote code, send by aldi IC Ledspots
  631. {
  632. name => 'IC Ledspot',
  633. id => '28',
  634. one => [1,-1],
  635. zero => [1,-2],
  636. start => [4,-5],
  637. clockabs => 600, #ca 600
  638. format => 'twostate',
  639. preamble => 'u28#', # prepend to converted message
  640. #clientmodule => '', # not used now
  641. #modulematch => '', # not used now
  642. length_min => '8',
  643. length_max => '8',
  644. },
  645. "29" => #
  646. {
  647. name => 'HT12e remote',
  648. id => '29',
  649. one => [-2,1],
  650. zero => [-1,2],
  651. #float => [1,-1],
  652. start => [-38,1], # Message is not provided as MS, worakround is start
  653. clockabs => 220, #ca 220
  654. format => 'tristate', # there is a pause puls between words
  655. preamble => 'u29#', # prepend to converted message
  656. #clientmodule => '', # not used now
  657. #modulematch => '', # not used now
  658. length_min => '10',
  659. length_max => '12', # message has only 10 bit but is paddet to 12
  660. },
  661. "30" => # a unitec remote door reed switch
  662. {
  663. name => 'unitec47031',
  664. comment => 'developModule. SD_UT module is only in github available',
  665. id => '30',
  666. developId => 'm',
  667. one => [-1,2],
  668. zero => [-2,1],
  669. start => [-33,1], # Message is not provided as MS, worakround is start
  670. clockabs => 300, # ca 300 us
  671. format => 'twostate', # there is a pause puls between words
  672. preamble => 'u30#', # prepend to converted message
  673. clientmodule => 'SD_UT', # not used now
  674. modulematch => '^u30', # not used now
  675. length_min => '12',
  676. length_max => '12', # message has only 10 bit but is paddet to 12
  677. },
  678. "31" => # Pollin Isotronic
  679. {
  680. name => 'pollin isotronic',
  681. id => '31',
  682. one => [-1,2],
  683. zero => [-2,1],
  684. start => [1],
  685. clockabs => 600,
  686. format => 'twostate',
  687. preamble => 'u31#', # prepend to converted message
  688. #clientmodule => '', # not used now
  689. #modulematch => '', # not used now
  690. length_min => '20',
  691. length_max => '20',
  692. },
  693. "32" => #FreeTec PE-6946 -> http://www.free-tec.de/Funkklingel-mit-Voic-PE-6946-919.shtml
  694. {
  695. name => 'freetec 6946',
  696. id => '32',
  697. one => [4,-2],
  698. zero => [1,-5],
  699. sync => [1,-49],
  700. clockabs => 140, #ca 140us
  701. format => 'twostate',
  702. preamble => 'u32#', # prepend to converted message
  703. #clientmodule => '', # not used now
  704. #modulematch => '', # not used now
  705. length_min => '24',
  706. length_max => '24',
  707. },
  708. "33" => #Thermo-/Hygrosensor S014
  709. {
  710. name => 'weather33', #
  711. id => '33',
  712. one => [1,-8],
  713. zero => [1,-4],
  714. sync => [1,-15],
  715. clockabs => '500', # not used now
  716. format => 'twostate', # not used now
  717. preamble => 'W33#', # prepend to converted message
  718. postamble => '', # Append to converted message
  719. clientmodule => 'SD_WS', # not used now
  720. #modulematch => '', # not used now
  721. length_min => '42',
  722. length_max => '44',
  723. },
  724. # "34" => # replaced by 37
  725. # {
  726. # name => 'unknown34',
  727. # id => '34',
  728. # one => [2,-1],
  729. # zero => [1,-2],
  730. # start => [3,-3,3,-3,3,-3,3,-3],
  731. # clockabs => '240',
  732. # format => 'twostate', # not used now
  733. # preamble => 'u34#', # prepend to converted message
  734. # postamble => '', # Append to converted message
  735. # #clientmodule => '', # not used now
  736. # #modulematch => '', # not used now
  737. # length_min => '40',
  738. # length_max => '40',
  739. # },
  740. "35" =>
  741. {
  742. name => 'socket35',
  743. id => '35',
  744. one => [1,-4],
  745. zero => [4,-1],
  746. sync => [1,-19],
  747. clockabs => '280',
  748. format => 'twostate', # not used now
  749. preamble => 'u35#', # prepend to converted message
  750. postamble => '', # Append to converted message
  751. #clientmodule => '', # not used now
  752. #modulematch => '', # not used now
  753. length_min => '28',
  754. length_max => '32',
  755. },
  756. "36" =>
  757. {
  758. name => 'socket36',
  759. id => '36',
  760. one => [1,-3],
  761. zero => [1,-1],
  762. start => [20,-20],
  763. clockabs => '500',
  764. format => 'twostate', # not used now
  765. preamble => 'u36#', # prepend to converted message
  766. postamble => '', # Append to converted message
  767. #clientmodule => '', # not used now
  768. #modulematch => '', # not used now
  769. length_min => '24',
  770. length_max => '24',
  771. },
  772. "37" => ## Bresser 7009994
  773. # MU;P0=729;P1=-736;P2=483;P3=-251;P4=238;P5=-491;D=010101012323452323454523454545234523234545234523232345454545232345454545452323232345232340;CP=4;
  774. # MU;P0=-790;P1=-255;P2=474;P4=226;P6=722;P7=-510;D=721060606060474747472121212147472121472147212121214747212147474721214747212147214721212147214060606060474747472121212140;CP=4;R=216;
  775. # short pulse of 250 us followed by a 500 us gap is a 0 bit
  776. # long pulse of 500 us followed by a 250 us gap is a 1 bit
  777. # sync preamble of pulse, gap, 750 us each, repeated 4 times
  778. {
  779. name => 'Bresser 7009994',
  780. id => '37',
  781. one => [2,-1],
  782. zero => [1,-2],
  783. start => [3,-3,3,-3],
  784. clockabs => '250',
  785. format => 'twostate', # not used now
  786. preamble => 'W37#', # prepend to converted message
  787. clientmodule => 'SD_WS',
  788. length_min => '40',
  789. length_max => '41',
  790. },
  791. "38" =>
  792. {
  793. name => 'weather38',
  794. id => '38',
  795. one => [1,-10],
  796. zero => [1,-5],
  797. sync => [1,-25],
  798. clockabs => '360', # not used now
  799. format => 'twostate', # not used now
  800. preamble => 's', # prepend to converted message
  801. postamble => '00', # Append to converted message
  802. clientmodule => 'CUL_TCM97001', # not used now
  803. #modulematch => '^s[A-Fa-f0-9]+', # not used now
  804. length_min => '32',
  805. length_max => '32',
  806. paddingbits => '8',
  807. },
  808. "39" => ## X10 Protocol
  809. {
  810. name => 'X10 Protocol',
  811. id => '39',
  812. one => [1,-3],
  813. zero => [1,-1],
  814. start => [17,-7],
  815. clockabs => 560,
  816. format => 'twostate',
  817. preamble => '', # prepend to converted message
  818. clientmodule => 'RFXX10REC', # not used now
  819. #modulematch => '^TX......', # not used now
  820. length_min => '32',
  821. length_max => '44',
  822. paddingbits => '8',
  823. postDemodulation => \&SIGNALduino_lengtnPrefix,
  824. filterfunc => 'SIGNALduino_compPattern',
  825. },
  826. "40" => ## Romotec
  827. {
  828. name => 'romotec',
  829. id => '40',
  830. one => [3,-2],
  831. zero => [1,-3],
  832. start => [1,-2],
  833. clockabs => 250,
  834. preamble => 'u40#', # prepend to converted message
  835. #clientmodule => '', # not used now
  836. #modulematch => '', # not used now
  837. length_min => '10',
  838. length_min => '12',
  839. },
  840. "41" => ## Elro (Smartwares) Doorbell DB200
  841. {
  842. name => 'elro doorbell',
  843. comment => 'Elro (Smartwares) Doorbell DB200',
  844. id => '41',
  845. zero => [1,-3],
  846. one => [3,-1],
  847. sync => [1,-15],
  848. clockabs => 450,
  849. preamble => 'u41#', # prepend to converted message
  850. #clientmodule => '', # not used now
  851. #modulematch => '', # not used now
  852. length_min => '20',
  853. },
  854. #"42" => ## MKT Multi Kon Trade // Sollte eigentlich als MS ITv1 erkannt werden
  855. # {
  856. # name => 'MKT motionsensor',
  857. # id => '42',
  858. # zero => [1,-3],
  859. # one => [3,-1],
  860. # sync => [-28],
  861. # clockabs => 550,
  862. # preamble => 'u42#', # prepend to converted message
  863. # #clientmodule => '', # not used now
  864. # #modulematch => '',
  865. # length_min => '24',
  866. # },
  867. "43" => ## Somfy RTS
  868. {
  869. name => 'Somfy RTS',
  870. id => '43',
  871. clockrange => [610,680], # min , max
  872. format => 'manchester',
  873. preamble => 'Ys',
  874. clientmodule => 'SOMFY', # not used now
  875. modulematch => '^Ys[0-9A-F]{14}',
  876. length_min => '56',
  877. length_max => '57',
  878. method => \&SIGNALduino_SomfyRTS, # Call to process this message
  879. msgIntro => 'SR;P0=-2560;P1=2560;P3=-640;D=10101010101010113;',
  880. #msgOutro => 'SR;P0=-30415;D=0;',
  881. frequency => '10AB85550A',
  882. },
  883. "44" => ## Bresser Temeo Trend
  884. {
  885. name => 'BresserTemeo',
  886. id => '44',
  887. clockabs => 500,
  888. zero => [4,-4],
  889. one => [4,-8],
  890. start => [8,-8],
  891. preamble => 'W44#',
  892. clientmodule => 'SD_WS',
  893. modulematch => '^W44#[A-F0-9]{18}',
  894. length_min => '64',
  895. length_max => '72',
  896. },
  897. "44.1" => ## Bresser Temeo Trend
  898. {
  899. name => 'BresserTemeo',
  900. id => '44',
  901. clockabs => 500,
  902. zero => [4,-4],
  903. one => [4,-8],
  904. start => [8,-12],
  905. preamble => 'W44x#',
  906. clientmodule => 'SD_WS',
  907. modulematch => '^W44x#[A-F0-9]{18}',
  908. length_min => '64',
  909. length_max => '72',
  910. },
  911. "45" => # Revolt
  912. # MU;P0=-8320;P1=9972;P2=-376;P3=117;P4=-251;P5=232;D=012345434345434345454545434345454545454543454343434343434343434343434543434345434343434545434345434343434343454343454545454345434343454345434343434343434345454543434343434345434345454543454343434543454345434545;CP=3;R=2
  913. {
  914. name => 'Revolt',
  915. id => '45',
  916. one => [2,-2],
  917. zero => [1,-2],
  918. start => [83,-3],
  919. clockabs => 120,
  920. preamble => 'r', # prepend to converted message
  921. clientmodule => 'Revolt',
  922. modulematch => '^r[A-Fa-f0-9]{22}',
  923. length_min => '84',
  924. length_max => '120',
  925. postDemodulation => sub { my ($name, @bit_msg) = @_; my @new_bitmsg = splice @bit_msg, 0,88; return 1,@new_bitmsg; },
  926. },
  927. "46" =>
  928. {
  929. name => 'EKX1BE',
  930. id => '46',
  931. one => [1,-8],
  932. zero => [8,-1],
  933. clockabs => 250, # -1=auto
  934. format => 'twostate', # not used now
  935. preamble => 'u46#',
  936. #clientmodule => '', # not used now
  937. #modulematch => '', # not used now
  938. length_min => '16',
  939. length_max => '18',
  940. },
  941. "47" => ## maverick
  942. {
  943. name => 'Maverick protocol',
  944. id => '47',
  945. clockrange => [180,260],
  946. format => 'manchester',
  947. preamble => 'P47#', # prepend to converted message
  948. clientmodule => 'SD_WS_Maverick',
  949. modulematch => '^P47#[569A]{12}.*',
  950. length_min => '100',
  951. length_max => '108',
  952. method => \&SIGNALduino_Maverick, # Call to process this message
  953. #polarity => 'invert'
  954. },
  955. "48" => ## Joker Dostmann TFA
  956. {
  957. name => 'TFA Dostmann',
  958. id => '48',
  959. clockabs => 250, # In real it is 500 but this leads to unprceise demodulation
  960. one => [-4,6],
  961. zero => [-4,2],
  962. start => [-6,2],
  963. format => 'twostate',
  964. preamble => 'U48#', # prepend to converted message
  965. #clientmodule => '', # not used now
  966. modulematch => '^U48#.*', # not used now
  967. length_min => '47',
  968. length_max => '48',
  969. },
  970. "49" => ## quigg / Aldi gt_9000
  971. {
  972. name => 'quigg_gt9000',
  973. id => '49',
  974. clockabs => 400,
  975. one => [2,-1],
  976. zero => [1,-3],
  977. start => [-15,2,-1],
  978. format => 'twostate',
  979. preamble => 'U49#', # prepend to converted message
  980. #clientmodule => '', # not used now
  981. modulematch => '^U49#.*', # not used now
  982. length_min => '22',
  983. length_max => '28',
  984. },
  985. "50" => ## Opus XT300
  986. {
  987. name => 'optus_XT300',
  988. id => '50',
  989. clockabs => 500,
  990. zero => [3,-2],
  991. one => [1,-2],
  992. # start => [1,-25], # Wenn das startsignal empfangen wird, fehlt das 1 bit
  993. format => 'twostate',
  994. preamble => 'W50#', # prepend to converted message
  995. clientmodule => 'SD_WS', # not used now
  996. modulematch => '^W50#.*', # not used now
  997. length_min => '47',
  998. length_max => '48',
  999. },
  1000. "51" =>
  1001. { # MS;P0=-16046;P1=552;P2=-1039;P3=983;P5=-7907;P6=-1841;P7=-4129;D=15161716171616161717171716161616161617161717171717171617171617161716161616161616171032323232;CP=1;SP=5;O;
  1002. name => 'weather51', # Logilink, NC, WS, TCM97001 etc.
  1003. comment => 'IAN 275901 Wetterstation Lidl',
  1004. id => '51',
  1005. one => [1,-8],
  1006. zero => [1,-4],
  1007. sync => [1,-13],
  1008. clockabs => '560', # not used now
  1009. format => 'twostate', # not used now
  1010. preamble => 'W51#', # prepend to converted message
  1011. postamble => '', # Append to converted message
  1012. clientmodule => 'SD_WS',
  1013. modulematch => '^W51#.*',
  1014. length_min => '40',
  1015. length_max => '45',
  1016. },
  1017. "52" => ## Oregon PIR Protocol
  1018. {
  1019. name => 'OS_PIR',
  1020. id => '52',
  1021. clockrange => [470,640], # min , max
  1022. format => 'manchester', # tristate can't be migrated from bin into hex!
  1023. clientmodule => 'OREGON',
  1024. modulematch => '^u52#F{3}|0{3}.*',
  1025. preamble => 'u52#',
  1026. length_min => '30',
  1027. length_max => '30',
  1028. method => \&SIGNALduino_OSPIR, # Call to process this message
  1029. polarity => 'invert',
  1030. },
  1031. "55" => ##quigg gt1000
  1032. {
  1033. name => 'quigg_gt1000',
  1034. id => '55',
  1035. clockabs => 300,
  1036. zero => [1,-4],
  1037. one => [4,-2],
  1038. sync => [1,-8],
  1039. format => 'twostate',
  1040. preamble => 'i', # prepend to converted message
  1041. clientmodule => 'IT', # not used now
  1042. modulematch => '^i.*', # not used now
  1043. length_min => '24',
  1044. length_max => '24',
  1045. },
  1046. "56" => ## Celexon
  1047. {
  1048. name => 'Celexon',
  1049. id => '56',
  1050. clockabs => 200,
  1051. zero => [1,-3],
  1052. one => [3,-1],
  1053. start => [25,-3],
  1054. format => 'twostate',
  1055. preamble => 'u56#', # prepend to converted message
  1056. #clientmodule => '' , # not used now
  1057. modulematch => '', # not used now
  1058. length_min => '56',
  1059. length_max => '68',
  1060. },
  1061. "57" => ## m-e doorbell
  1062. {
  1063. name => 'm-e',
  1064. id => '57',
  1065. clockrange => [300,360], # min , max
  1066. format => 'manchester', # tristate can't be migrated from bin into hex!
  1067. clientmodule => '',
  1068. modulematch => '^u57*',
  1069. preamble => 'u57#',
  1070. length_min => '21',
  1071. length_max => '24',
  1072. method => \&SIGNALduino_MCRAW, # Call to process this message
  1073. polarity => 'invert',
  1074. },
  1075. "58" => ## tfa 30.3208.0
  1076. {
  1077. name => 'tfa 30.3208.0 ',
  1078. id => '58',
  1079. clockrange => [460,520], # min , max
  1080. format => 'manchester', # tristate can't be migrated from bin into hex!
  1081. clientmodule => '',
  1082. modulematch => '^W58*',
  1083. preamble => 'W58#',
  1084. length_min => '54',
  1085. length_max => '136',
  1086. method => \&SIGNALduino_MCTFA, # Call to process this message
  1087. polarity => 'invert',
  1088. },
  1089. "59" => ## AK-HD-4 remote
  1090. {
  1091. name => 'AK-HD-4',
  1092. id => '59',
  1093. clockabs => 230,
  1094. zero => [-4,1],
  1095. one => [-1,4],
  1096. start => [-1,37],
  1097. format => 'twostate', # tristate can't be migrated from bin into hex!
  1098. preamble => 'u59#', # Append to converted message
  1099. postamble => '', # Append to converted message
  1100. #clientmodule => '', # not used now
  1101. modulematch => '', # not used now
  1102. length_min => '24',
  1103. length_max => '24',
  1104. },
  1105. "60" => ## ELV, LA CROSSE (WS2000/WS7000)
  1106. {
  1107. # MU;P0=32001;P1=-381;P2=835;P3=354;P4=-857;D=01212121212121212121343421212134342121213434342121343421212134213421213421212121342121212134212121213421212121343421343430;CP=2;R=53; # tested sensors: WS-7000-20, AS2000, ASH2000, S2000, S2000I, S2001A, S2001IA,
  1108. # ASH2200, S300IA, S2001I, S2000ID, S2001ID, S2500H
  1109. # not tested: AS3, S2000W, S2000R, WS7000-15, WS7000-16, WS2500-19, S300TH, S555TH
  1110. # das letzte Bit 1 und 1 x 0 Preambel fehlt meistens
  1111. # ___ _
  1112. # | |_ | |___
  1113. # Bit 0 Bit 1
  1114. # kurz 366 µSek / lang 854 µSek / gesamt 1220 µSek - Sollzeiten
  1115. name => 'WS2000',
  1116. id => '60',
  1117. one => [3,-7],
  1118. zero => [7,-3],
  1119. clockabs => 122,
  1120. preamble => 'K', # prepend to converted message
  1121. postamble => '', # Append to converted message
  1122. clientmodule => 'CUL_WS',
  1123. length_min => '44', # eigentlich 46
  1124. length_max => '82', # eigentlich 81
  1125. postDemodulation => \&SIGNALduino_postDemo_WS2000,
  1126. },
  1127. "61" => ## ELV FS10
  1128. # tested transmitter: FS10-S8, FS10-S4, FS10-ZE
  1129. # tested receiver: FS10-ST, FS10-MS, WS3000-TV, PC-Wettersensor-Empfaenger
  1130. # das letzte Bit 1 und 1 x 0 Preambel fehlt immer
  1131. {
  1132. name => 'FS10',
  1133. id => '61',
  1134. one => [1,-2],
  1135. zero => [1,-1],
  1136. clockabs => 400,
  1137. format => 'twostate',
  1138. preamble => 'P61#', # prepend to converted message
  1139. postamble => '', # Append to converted message
  1140. clientmodule => 'FS10',
  1141. #modulematch => '',
  1142. length_min => '38', # eigentlich 41 oder 46 (Pruefsumme nicht bei allen)
  1143. length_max => '48', # eigentlich 46
  1144. },
  1145. "62" => ## Clarus_Switch
  1146. { #MU;P0=-5893;P4=-634;P5=498;P6=-257;P7=116;D=45656567474747474745656707456747474747456745674567456565674747474747456567074567474747474567456745674565656747474747474565670745674747474745674567456745656567474747474745656707456747474747456745674567456565674747474747456567074567474747474567456745674567;CP=7;O;
  1147. name => 'Clarus_Switch',
  1148. id => '62',
  1149. one => [3,-1],
  1150. zero => [1,-3],
  1151. start => [1,-35], # ca 30-40
  1152. clockabs => 189,
  1153. preamble => 'i', # prepend to converted message
  1154. clientmodule => 'IT',
  1155. #modulematch => '',
  1156. length_min => '24',
  1157. length_max => '24',
  1158. },
  1159. "63" => ## Warema MU
  1160. { #MU;P0=-2988;P1=1762;P2=-1781;P3=-902;P4=871;P5=6762;P6=5012;D=0121342434343434352434313434243521342134343436;
  1161. name => 'Warema',
  1162. comment => 'developId, is still experimental',
  1163. id => '63',
  1164. developId => 'y',
  1165. one => [1],
  1166. zero => [0],
  1167. clockabs => 800,
  1168. syncabs => '6700',# Special field for filterMC function
  1169. preamble => 'u63', # prepend to converted message
  1170. #clientmodule => '',
  1171. #modulematch => '',
  1172. length_min => '24',
  1173. filterfunc => 'SIGNALduino_filterMC',
  1174. },
  1175. "64" => ## WH2 #############################################################################
  1176. {
  1177. # MU;P0=-32001;P1=457;P2=-1064;P3=1438;D=0123232323212121232123232321212121212121212323212121232321;CP=1;R=63;
  1178. # MU;P0=-32001;P1=473;P2=-1058;P3=1454;D=0123232323212121232123232121212121212121212121232321212321;CP=1;R=51;
  1179. #MU;P0=134;P1=-113;P3=412;P4=-1062;P5=1379;D=01010101013434343434343454345454345454545454345454545454343434545434345454345454545454543454543454345454545434545454345;CP=3;
  1180. name => 'WH2',
  1181. id => '64',
  1182. one => [1,-2],
  1183. zero => [3,-2],
  1184. clockabs => 490,
  1185. clientmodule => 'SD_WS',
  1186. modulematch => '^W64*',
  1187. preamble => 'W64#', # prepend to converted message
  1188. postamble => '', # Append to converted message
  1189. #clientmodule => '',
  1190. length_min => '48',
  1191. length_max => '54',
  1192. },
  1193. "65" => ## Homeeasy
  1194. {
  1195. name => 'Homeeasy',
  1196. id => '65',
  1197. one => [1,-5],
  1198. zero => [1,-1],
  1199. start => [1,-40],
  1200. clockabs => 250,
  1201. format => 'twostate', # not used now
  1202. preamble => 'U65#',
  1203. length_min => '50',
  1204. #msgOutro => 'SR;P0=275;P1=-7150;D=01;',
  1205. postDemodulation => \&SIGNALduino_HE,
  1206. },
  1207. "66" => ## TX2 Protocol (Remote Temp Transmitter & Remote Thermo Model 7035)
  1208. # MU;P0=13312;P1=-2785;P2=4985;P3=1124;P4=-6442;P5=3181;P6=-31980;D=0121345434545454545434545454543454545434343454543434545434545454545454343434545434343434545621213454345454545454345454545434545454343434545434345454345454545454543434345454343434345456212134543454545454543454545454345454543434345454343454543454545454545;CP=3;R=73;O;
  1209. {
  1210. name => 'WS7035',
  1211. id => '66',
  1212. one => [10,-52],
  1213. zero => [27,-52],
  1214. start => [-21,42,-21],
  1215. clockabs => 122,
  1216. format => 'pwm', # not used now
  1217. preamble => 'TX',
  1218. clientmodule => 'CUL_TX',
  1219. modulematch => '^TX......',
  1220. length_min => '43',
  1221. length_max => '44',
  1222. postDemodulation => \&SIGNALduino_postDemo_WS7035,
  1223. },
  1224. "67" => ## TX2 Protocol (Remote Datalink & Remote Thermo Model 7053)
  1225. # MU;P0=3381;P1=-672;P2=-4628;P3=1142;P4=-30768;D=0102320232020202020232020232020202320232323202323202020202020202020401023202320202020202320202320202023202323232023232020202020202020200;CP=0;R=45;
  1226. # MU;P0=1148;P1=3421;P6=-664;P7=-4631;D=16170717071717171717071717071717171717070707170717171717070717171710;CP=1;R=29;
  1227. # MU;P0=3389;P3=2560;P4=-720;P5=1149;P7=-4616;D=345407570757070707070757070757070707070757570707075707070707570757575;CP=5;R=253;
  1228. # __ ____
  1229. # ________| | ________| |
  1230. # Bit 1 Bit 0
  1231. # 4630 1220 4630 3420 µSek - mit Oszi gemessene Zeiten
  1232. {
  1233. name => 'WS7053',
  1234. id => '67',
  1235. one => [-38,10],
  1236. zero => [-38,28],
  1237. clockabs => 122,
  1238. preamble => 'TX', # prepend to converted message
  1239. clientmodule => 'CUL_TX',
  1240. modulematch => '^TX......',
  1241. length_min => '32',
  1242. length_max => '34',
  1243. postDemodulation => \&SIGNALduino_postDemo_WS7053,
  1244. },
  1245. "68" => ## PFR-130 ###########################################################################
  1246. {
  1247. # MS;P0=-3890;P1=386;P2=-2191;P3=-8184;D=1312121212121012121212121012121212101012101010121012121210121210101210101012;CP=1;SP=3;R=20;O;
  1248. # MS;P0=-2189;P1=371;P2=-3901;P3=-8158;D=1310101010101210101010101210101010121210121212101210101012101012121012121210;CP=1;SP=3;R=20;O;
  1249. name => 'PFR-130',
  1250. id => '68',
  1251. one => [1,-10],
  1252. zero => [1,-5],
  1253. sync => [1,-21],
  1254. clockabs => 380, # not used now
  1255. preamble => 's', # prepend to converted message
  1256. postamble => '00', # Append to converted message
  1257. clientmodule => 'CUL_TCM97001', # not used now
  1258. length_min => '24',
  1259. length_max => '42',
  1260. paddingbits => '8', # pad up to 8 bits, default is 4
  1261. },
  1262. "69" => ## Hoermann
  1263. # MU;P0=-508;P1=1029;P2=503;P3=-1023;P4=12388;D=01010232323232310104010101010101010102323231010232310231023232323231023101023101010231010101010232323232310104010101010101010102323231010232310231023232323231023101023101010231010101010232323232310104010101010101010102323231010232310231023232323231023101;CP=2;R=37;O;
  1264. {
  1265. name => 'Hoermann',
  1266. id => '69',
  1267. zero => [2,-1],
  1268. one => [1,-2],
  1269. start => [24,-1],
  1270. clockabs => 510,
  1271. format => 'twostate', # not used now
  1272. #clientmodule => '',
  1273. #modulematch => '^U69*',
  1274. preamble => 'U69#',
  1275. length_min => '40',
  1276. #length_max => '90',
  1277. postDemodulation => \&SIGNALduino_postDemo_Hoermann, # Call to process this message
  1278. },
  1279. "70" => ## FHT80TF (Funk-Tuer-Fenster-Melder FHT 80TF und FHT 80TF-2)
  1280. # closed MU;P0=-24396;P1=417;P2=-376;P3=610;P4=-582;D=012121212121212121212121234123434121234341212343434121234123434343412343434121234341212121212341212341234341234123434;CP=1;R=35;
  1281. # open MU;P0=-21652;P1=429;P2=-367;P4=634;P5=-555;D=012121212121212121212121245124545121245451212454545121245124545454512454545121245451212121212124512451245451245121212;CP=1;R=38;
  1282. {
  1283. name => 'FHT80TF',
  1284. comment => 'Door/Window switch (868Mhz)',
  1285. id => '70',
  1286. one => [1.5,-1.5], # 600
  1287. zero => [1,-1], # 400
  1288. clockabs => 400,
  1289. format => 'twostate', # not used now
  1290. clientmodule => 'CUL_FHTTK',
  1291. preamble => 'T',
  1292. length_min => '50',
  1293. length_max => '58',
  1294. postDemodulation => \&SIGNALduino_postDemo_FHT80TF,
  1295. },
  1296. "71" => ## PV-8644 infactory Poolthermometer
  1297. # MU;P0=1735;P1=-1160;P2=591;P3=-876;D=0123012323010101230101232301230123010101010123012301012323232323232301232323232323232323012301012;CP=2;R=97;
  1298. {
  1299. name => 'PV-8644',
  1300. comment => 'infactory Poolthermometer',
  1301. id => '71',
  1302. clockabs => 580,
  1303. zero => [3,-2],
  1304. one => [1,-1.5],
  1305. format => 'twostate',
  1306. preamble => 'W71#', # prepend to converted message
  1307. clientmodule => 'SD_WS',
  1308. #modulematch => '^W71#.*'
  1309. length_min => '48',
  1310. length_max => '48',
  1311. },
  1312. # MU;P0=-760;P1=334;P2=693;P3=-399;P4=-8942;P5=4796;P6=-1540;D=01010102310232310101010102310232323101010102310101010101023102323102323102323102310101010102310232323101010102310101010101023102310231023102456102310232310232310231010101010231023232310101010231010101010102310231023102310245610231023231023231023101010101;CP=1;R=45;O;
  1313. # MU;P0=-8848;P1=4804;P2=-1512;P3=336;P4=-757;P5=695;P6=-402;D=0123456345656345656345634343434345634565656343434345634343434343456345634563456345;CP=3;R=49;
  1314. "72" => # Siro blinds MU @Dr. Smag
  1315. {
  1316. name => 'Siro shutter',
  1317. comment => 'developModule. Siro is not in github or SVN available',
  1318. id => '72',
  1319. developId => 'm',
  1320. dispatchequals => 'true',
  1321. one => [2,-1.2], # 680, -400
  1322. zero => [1,-2.2], # 340, -750
  1323. start => [14,-4.4], # 4800,-1520
  1324. clockabs => 340,
  1325. format => 'twostate',
  1326. preamble => 'P72#', # prepend to converted message
  1327. clientmodule => 'Siro',
  1328. #modulematch => '',
  1329. length_min => '39',
  1330. length_max => '40',
  1331. msgOutro => 'SR;P0=-8500;D=0;',
  1332. },
  1333. # MS;P0=4803;P1=-1522;P2=333;P3=-769;P4=699;P5=-393;P6=-9190;D=2601234523454523454523452323232323452345454523232323452323232323234523232345454545;CP=2;SP=6;R=61;
  1334. "72.1" => # Siro blinds MS @Dr. Smag
  1335. {
  1336. name => 'Siro shutter',
  1337. comment => 'developModule. Siro is not in github or SVN available',
  1338. id => '72',
  1339. developId => 'm',
  1340. dispatchequals => 'true',
  1341. one => [2,-1.2], # 680, -400
  1342. zero => [1,-2.2], # 340, -750
  1343. sync => [14,-4.4], # 4800,-1520
  1344. clockabs => 340,
  1345. format => 'twostate',
  1346. preamble => 'P72#', # prepend to converted message
  1347. clientmodule => 'Siro',
  1348. #modulematch => '',
  1349. length_min => '39',
  1350. length_max => '40',
  1351. #msgOutro => 'SR;P0=-8500;D=0;',
  1352. },
  1353. "73" => ## FHT80 - Raumthermostat (868Mhz), @HomeAutoUser
  1354. {
  1355. name => 'FHT80',
  1356. comment => 'Roomthermostat (868Mhz only receive)',
  1357. id => '73',
  1358. developId => 'y',
  1359. one => [1.5,-1.5], # 600
  1360. zero => [1,-1], # 400
  1361. clockabs => 400,
  1362. format => 'twostate', # not used now
  1363. clientmodule => 'FHT',
  1364. preamble => '810c04xx0909a001',
  1365. length_min => '59',
  1366. length_max => '67',
  1367. postDemodulation => \&SIGNALduino_postDemo_FHT80,
  1368. },
  1369. "74" => ## FS20 - 'Remote Control (868Mhz), @HomeAutoUser
  1370. {
  1371. name => 'FS20',
  1372. comment => 'Remote Control (868Mhz only receive)',
  1373. id => '74',
  1374. developId => 'y',
  1375. one => [1.5,-1.5], # 600
  1376. zero => [1,-1], # 400
  1377. clockabs => 400,
  1378. format => 'twostate', # not used now
  1379. clientmodule => 'FS20',
  1380. preamble => '810b04f70101a001',
  1381. length_min => '50',
  1382. length_max => '67',
  1383. postDemodulation => \&SIGNALduino_postDemo_FS20,
  1384. },
  1385. "75" => ## ConradRSL2 @litronics https://github.com/RFD-FHEM/SIGNALDuino/issues/69
  1386. # MU;P0=-1365;P1=477;P2=1145;P3=-734;P4=-6332;D=01023202310102323102423102323102323101023232323101010232323231023102323102310102323102423102323102323101023232323101010232323231023102323102310102323102;CP=1;R=12;
  1387. {
  1388. name => 'ConradRSL2',
  1389. id => '75',
  1390. one => [3,-1],
  1391. zero => [1,-3],
  1392. clockabs => 500,
  1393. format => 'twostate',
  1394. clientmodule => 'SD_RSL',
  1395. preamble => 'P1#',
  1396. modulematch => '^P1#[A-Fa-f0-9]{8}',
  1397. length_min => '32',
  1398. length_max => '40',
  1399. },
  1400. "76" => ## Kabellose LED-Weihnachtskerzen XM21-0
  1401. {
  1402. name => 'xm21',
  1403. comment => 'reserviert, LED Lichtrekette on',
  1404. id => '76',
  1405. developId => 'p',
  1406. one => [1.2,-2], # 120,-200
  1407. zero => [], # existiert nicht
  1408. start => [4.5,-2], # 450,-200 Starsequenz
  1409. clockabs => 100,
  1410. format => 'twostate', # not used now
  1411. clientmodule => '',
  1412. preamble => 'P76',
  1413. length_min => 64,
  1414. length_max => 64,
  1415. },
  1416. "76.1" => ## Kabellose LED-Weihnachtskerzen XM21-0
  1417. {
  1418. name => 'xm21',
  1419. comment => 'reserviert, LED Lichtrekette off',
  1420. id => '76.1',
  1421. developId => 'p',
  1422. one => [1.2,-2], # 120,-200
  1423. zero => [], # existiert nicht
  1424. start => [4.5,-2], # 450,-200 Starsequenz
  1425. clockabs => 100,
  1426. format => 'twostate', # not used now
  1427. clientmodule => '',
  1428. preamble => 'P76',
  1429. length_min => 58,
  1430. length_max => 58,
  1431. },
  1432. );
  1433. sub
  1434. SIGNALduino_Initialize($)
  1435. {
  1436. my ($hash) = @_;
  1437. require "$attr{global}{modpath}/FHEM/DevIo.pm";
  1438. # Provider
  1439. $hash->{ReadFn} = "SIGNALduino_Read";
  1440. $hash->{WriteFn} = "SIGNALduino_Write";
  1441. $hash->{ReadyFn} = "SIGNALduino_Ready";
  1442. # Normal devices
  1443. $hash->{DefFn} = "SIGNALduino_Define";
  1444. $hash->{FingerprintFn} = "SIGNALduino_FingerprintFn";
  1445. $hash->{UndefFn} = "SIGNALduino_Undef";
  1446. $hash->{GetFn} = "SIGNALduino_Get";
  1447. $hash->{SetFn} = "SIGNALduino_Set";
  1448. $hash->{AttrFn} = "SIGNALduino_Attr";
  1449. $hash->{AttrList} =
  1450. "Clients MatchList do_not_notify:1,0 dummy:1,0"
  1451. ." hexFile"
  1452. ." initCommands"
  1453. ." flashCommand"
  1454. ." hardware:nano328,uno,promini328,nanoCC1101"
  1455. ." debug:0,1"
  1456. ." longids"
  1457. ." minsecs"
  1458. ." whitelist_IDs"
  1459. ." blacklist_IDs"
  1460. ." WS09_CRCAUS:0,1,2"
  1461. ." addvaltrigger"
  1462. ." rawmsgEvent:1,0"
  1463. ." cc1101_frequency"
  1464. ." doubleMsgCheck_IDs"
  1465. ." suppressDeviceRawmsg:1,0"
  1466. ." development"
  1467. ." noMsgVerbose:0,1,2,3,4,5"
  1468. ." $readingFnAttributes";
  1469. $hash->{ShutdownFn} = "SIGNALduino_Shutdown";
  1470. $hash->{msIdList} = ();
  1471. $hash->{muIdList} = ();
  1472. $hash->{mcIdList} = ();
  1473. }
  1474. sub
  1475. SIGNALduino_FingerprintFn($$)
  1476. {
  1477. my ($name, $msg) = @_;
  1478. # Store only the "relevant" part, as the Signalduino won't compute the checksum
  1479. #$msg = substr($msg, 8) if($msg =~ m/^81/ && length($msg) > 8);
  1480. return ($name, $msg);
  1481. }
  1482. #####################################
  1483. sub
  1484. SIGNALduino_Define($$)
  1485. {
  1486. my ($hash, $def) = @_;
  1487. my @a = split("[ \t][ \t]*", $def);
  1488. if(@a != 3) {
  1489. my $msg = "wrong syntax: define <name> SIGNALduino {none | devicename[\@baudrate] | devicename\@directio | hostname:port}";
  1490. Log3 undef, 2, $msg;
  1491. return $msg;
  1492. }
  1493. DevIo_CloseDev($hash);
  1494. my $name = $a[0];
  1495. if (!exists &round)
  1496. {
  1497. Log3 $name, 1, "$name: Signalduino can't be activated (sub round not found). Please update Fhem via update command";
  1498. return undef;
  1499. }
  1500. my $dev = $a[2];
  1501. #Debug "dev: $dev" if ($debug);
  1502. #my $hardware=AttrVal($name,"hardware","nano328");
  1503. #Debug "hardware: $hardware" if ($debug);
  1504. if($dev eq "none") {
  1505. Log3 $name, 1, "$name: device is none, commands will be echoed only";
  1506. $attr{$name}{dummy} = 1;
  1507. #return undef;
  1508. }
  1509. if ($dev ne "none" && $dev =~ m/[a-zA-Z]/ && $dev !~ m/\@/) { # bei einer IP wird kein \@57600 angehaengt
  1510. $dev .= "\@57600";
  1511. }
  1512. #$hash->{CMDS} = "";
  1513. $hash->{Clients} = $clientsSIGNALduino;
  1514. $hash->{MatchList} = \%matchListSIGNALduino;
  1515. #if( !defined( $attr{$name}{hardware} ) ) {
  1516. # $attr{$name}{hardware} = "nano328";
  1517. #}
  1518. if( !defined( $attr{$name}{flashCommand} ) ) {
  1519. # $attr{$name}{flashCommand} = "avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]"
  1520. $attr{$name}{flashCommand} = "avrdude -c arduino -b [BAUDRATE] -P [PORT] -p atmega328p -vv -U flash:w:[HEXFILE] 2>[LOGFILE]";
  1521. }
  1522. $hash->{DeviceName} = $dev;
  1523. my $ret=undef;
  1524. InternalTimer(gettimeofday(), 'SIGNALduino_IdList',"sduino_IdList:$name",0); # verzoegern bis alle Attribute eingelesen sind
  1525. if($dev ne "none") {
  1526. $ret = DevIo_OpenDev($hash, 0, "SIGNALduino_DoInit", 'SIGNALduino_Connect');
  1527. } else {
  1528. $hash->{DevState} = 'initialized';
  1529. readingsSingleUpdate($hash, "state", "opened", 1);
  1530. }
  1531. $hash->{DMSG}="nothing";
  1532. $hash->{LASTDMSG} = "nothing";
  1533. $hash->{TIME}=time();
  1534. Log3 $name, 3, "$name: Firmwareversion: ".$hash->{READINGS}{version}{VAL} if ($hash->{READINGS}{version}{VAL});
  1535. return $ret;
  1536. }
  1537. ###############################
  1538. sub SIGNALduino_Connect($$)
  1539. {
  1540. my ($hash, $err) = @_;
  1541. # damit wird die err-msg nur einmal ausgegeben
  1542. if (!defined($hash->{disConnFlag}) && $err) {
  1543. SIGNALduino_Log3($hash, 3, "SIGNALduino $hash->{NAME}: ${err}");
  1544. Log3($hash, 3, "SIGNALduino $hash->{NAME}: ${err}");
  1545. $hash->{disConnFlag} = 1;
  1546. }
  1547. }
  1548. #####################################
  1549. sub
  1550. SIGNALduino_Undef($$)
  1551. {
  1552. my ($hash, $arg) = @_;
  1553. my $name = $hash->{NAME};
  1554. foreach my $d (sort keys %defs) {
  1555. if(defined($defs{$d}) &&
  1556. defined($defs{$d}{IODev}) &&
  1557. $defs{$d}{IODev} == $hash)
  1558. {
  1559. my $lev = ($reread_active ? 4 : 2);
  1560. Log3 $name, $lev, "$name: deleting port for $d";
  1561. delete $defs{$d}{IODev};
  1562. }
  1563. }
  1564. SIGNALduino_Shutdown($hash);
  1565. DevIo_CloseDev($hash);
  1566. RemoveInternalTimer($hash);
  1567. return undef;
  1568. }
  1569. #####################################
  1570. sub
  1571. SIGNALduino_Shutdown($)
  1572. {
  1573. my ($hash) = @_;
  1574. #DevIo_SimpleWrite($hash, "XQ\n",2);
  1575. SIGNALduino_SimpleWrite($hash, "XQ"); # Switch reception off, it may hang up the SIGNALduino
  1576. return undef;
  1577. }
  1578. #####################################
  1579. #$hash,$name,"sendmsg","P17;R6#".substr($arg,2)
  1580. sub
  1581. SIGNALduino_Set($@)
  1582. {
  1583. my ($hash, @a) = @_;
  1584. return "\"set SIGNALduino\" needs at least one parameter" if(@a < 2);
  1585. #Log3 $hash, 3, "SIGNALduino_Set called with params @a";
  1586. my $hasCC1101 = 0;
  1587. my $CC1101Frequency;
  1588. if ($hash->{version} && $hash->{version} =~ m/cc1101/) {
  1589. $hasCC1101 = 1;
  1590. if (!defined($hash->{cc1101_frequency})) {
  1591. $CC1101Frequency = "433";
  1592. } else {
  1593. $CC1101Frequency = $hash->{cc1101_frequency};
  1594. }
  1595. }
  1596. if (!defined($sets{$a[1]})) {
  1597. my $arguments = ' ';
  1598. foreach my $arg (sort keys %sets) {
  1599. next if ($arg =~ m/cc1101/ && $hasCC1101 == 0);
  1600. if ($arg =~ m/patable/) {
  1601. next if (substr($arg, -3) ne $CC1101Frequency);
  1602. }
  1603. $arguments.= $arg . ($sets{$arg} ? (':' . $sets{$arg}) : '') . ' ';
  1604. }
  1605. #Log3 $hash, 3, "set arg = $arguments";
  1606. return "Unknown argument $a[1], choose one of " . $arguments;
  1607. }
  1608. my $name = shift @a;
  1609. my $cmd = shift @a;
  1610. my $arg = join(" ", @a);
  1611. if ($cmd =~ m/cc1101/ && $hasCC1101 == 0) {
  1612. return "This command is only available with a cc1101 receiver";
  1613. }
  1614. return "$name is not active, may firmware is not suppoted, please flash or reset" if ($cmd ne 'reset' && $cmd ne 'flash' && exists($hash->{DevState}) && $hash->{DevState} ne 'initialized');
  1615. if ($cmd =~ m/^cc1101_/) {
  1616. $cmd = substr($cmd,7);
  1617. }
  1618. if($cmd eq "raw") {
  1619. Log3 $name, 4, "set $name $cmd $arg";
  1620. #SIGNALduino_SimpleWrite($hash, $arg);
  1621. SIGNALduino_AddSendQueue($hash,$arg);
  1622. } elsif( $cmd eq "flash" ) {
  1623. my @args = split(' ', $arg);
  1624. my $log = "";
  1625. my $hexFile = "";
  1626. my @deviceName = split('@', $hash->{DeviceName});
  1627. my $port = $deviceName[0];
  1628. my $hardware=AttrVal($name,"hardware","nano328");
  1629. my $baudrate=$hardware eq "uno" ? 115200 : 57600;
  1630. my $defaultHexFile = "./FHEM/firmware/$hash->{TYPE}_$hardware.hex";
  1631. my $logFile = AttrVal("global", "logdir", "./log/") . "$hash->{TYPE}-Flash.log";
  1632. if(!$arg || $args[0] !~ m/^(\w|\/|.)+$/) {
  1633. $hexFile = AttrVal($name, "hexFile", "");
  1634. if ($hexFile eq "") {
  1635. $hexFile = $defaultHexFile;
  1636. }
  1637. }
  1638. elsif ($args[0] =~ m/^https?:\/\// ) {
  1639. my $http_param = {
  1640. url => $args[0],
  1641. timeout => 5,
  1642. hash => $hash, # Muss gesetzt werden, damit die Callback funktion wieder $hash hat
  1643. method => "GET", # Lesen von Inhalten
  1644. callback => \&SIGNALduino_ParseHttpResponse, # Diese Funktion soll das Ergebnis dieser HTTP Anfrage bearbeiten
  1645. command => 'flash',
  1646. };
  1647. HttpUtils_NonblockingGet($http_param);
  1648. return;
  1649. } else {
  1650. $hexFile = $args[0];
  1651. }
  1652. Log3 $name, 3, "$name: filename $hexFile provided, trying to flash";
  1653. return "Usage: set $name flash [filename]\n\nor use the hexFile attribute" if($hexFile !~ m/^(\w|\/|.)+$/);
  1654. $log .= "flashing Arduino $name\n";
  1655. $log .= "hex file: $hexFile\n";
  1656. $log .= "port: $port\n";
  1657. $log .= "log file: $logFile\n";
  1658. my $flashCommand = AttrVal($name, "flashCommand", "");
  1659. if($flashCommand ne "") {
  1660. if (-e $logFile) {
  1661. unlink $logFile;
  1662. }
  1663. DevIo_CloseDev($hash);
  1664. $hash->{STATE} = "disconnected";
  1665. $log .= "$name closed\n";
  1666. my $avrdude = $flashCommand;
  1667. $avrdude =~ s/\Q[PORT]\E/$port/g;
  1668. $avrdude =~ s/\Q[BAUDRATE]\E/$baudrate/g;
  1669. $avrdude =~ s/\Q[HEXFILE]\E/$hexFile/g;
  1670. $avrdude =~ s/\Q[LOGFILE]\E/$logFile/g;
  1671. $log .= "command: $avrdude\n\n";
  1672. `$avrdude`;
  1673. local $/=undef;
  1674. if (-e $logFile) {
  1675. open FILE, $logFile;
  1676. my $logText = <FILE>;
  1677. close FILE;
  1678. $log .= "--- AVRDUDE ---------------------------------------------------------------------------------\n";
  1679. $log .= $logText;
  1680. $log .= "--- AVRDUDE ---------------------------------------------------------------------------------\n\n";
  1681. }
  1682. else {
  1683. $log .= "WARNING: avrdude created no log file\n\n";
  1684. }
  1685. }
  1686. else {
  1687. $log .= "\n\nNo flashCommand found. Please define this attribute.\n\n";
  1688. }
  1689. DevIo_OpenDev($hash, 0, "SIGNALduino_DoInit", 'SIGNALduino_Connect');
  1690. $log .= "$name opened\n";
  1691. return $log;
  1692. } elsif ($cmd =~ m/reset/i) {
  1693. delete($hash->{initResetFlag}) if defined($hash->{initResetFlag});
  1694. return SIGNALduino_ResetDevice($hash);
  1695. } elsif( $cmd eq "close" ) {
  1696. $hash->{DevState} = 'closed';
  1697. return SIGNALduino_CloseDevice($hash);
  1698. } elsif( $cmd eq "disableMessagetype" ) {
  1699. my $argm = 'CD' . substr($arg,-1,1);
  1700. #SIGNALduino_SimpleWrite($hash, $argm);
  1701. SIGNALduino_AddSendQueue($hash,$argm);
  1702. Log3 $name, 4, "set $name $cmd $arg $argm";;
  1703. } elsif( $cmd eq "enableMessagetype" ) {
  1704. my $argm = 'CE' . substr($arg,-1,1);
  1705. #SIGNALduino_SimpleWrite($hash, $argm);
  1706. SIGNALduino_AddSendQueue($hash,$argm);
  1707. Log3 $name, 4, "set $name $cmd $arg $argm";
  1708. } elsif( $cmd eq "freq" ) {
  1709. if ($arg eq "") {
  1710. $arg = AttrVal($name,"cc1101_frequency", 433.92);
  1711. }
  1712. my $f = $arg/26*65536;
  1713. my $f2 = sprintf("%02x", $f / 65536);
  1714. my $f1 = sprintf("%02x", int($f % 65536) / 256);
  1715. my $f0 = sprintf("%02x", $f % 256);
  1716. $arg = sprintf("%.3f", (hex($f2)*65536+hex($f1)*256+hex($f0))/65536*26);
  1717. Log3 $name, 3, "$name: Setting FREQ2..0 (0D,0E,0F) to $f2 $f1 $f0 = $arg MHz";
  1718. SIGNALduino_AddSendQueue($hash,"W0F$f2");
  1719. SIGNALduino_AddSendQueue($hash,"W10$f1");
  1720. SIGNALduino_AddSendQueue($hash,"W11$f0");
  1721. SIGNALduino_WriteInit($hash);
  1722. } elsif( $cmd eq "bWidth" ) {
  1723. SIGNALduino_AddSendQueue($hash,"C10");
  1724. $hash->{getcmd}->{cmd} = "bWidth";
  1725. $hash->{getcmd}->{arg} = $arg;
  1726. } elsif( $cmd eq "rAmpl" ) {
  1727. return "a numerical value between 24 and 42 is expected" if($arg !~ m/^\d+$/ || $arg < 24 || $arg > 42);
  1728. my ($v, $w);
  1729. for($v = 0; $v < @ampllist; $v++) {
  1730. last if($ampllist[$v] > $arg);
  1731. }
  1732. $v = sprintf("%02d", $v-1);
  1733. $w = $ampllist[$v];
  1734. Log3 $name, 3, "$name: Setting AGCCTRL2 (1B) to $v / $w dB";
  1735. SIGNALduino_AddSendQueue($hash,"W1D$v");
  1736. SIGNALduino_WriteInit($hash);
  1737. } elsif( $cmd eq "sens" ) {
  1738. return "a numerical value between 4 and 16 is expected" if($arg !~ m/^\d+$/ || $arg < 4 || $arg > 16);
  1739. my $w = int($arg/4)*4;
  1740. my $v = sprintf("9%d",$arg/4-1);
  1741. Log3 $name, 3, "$name: Setting AGCCTRL0 (1D) to $v / $w dB";
  1742. SIGNALduino_AddSendQueue($hash,"W1F$v");
  1743. SIGNALduino_WriteInit($hash);
  1744. } elsif( substr($cmd,0,7) eq "patable" ) {
  1745. my $paFreq = substr($cmd,8);
  1746. my $pa = "x" . $patable{$paFreq}{$arg};
  1747. Log3 $name, 3, "$name: Setting patable $paFreq $arg $pa";
  1748. SIGNALduino_AddSendQueue($hash,$pa);
  1749. SIGNALduino_WriteInit($hash);
  1750. } elsif( $cmd eq "sendMsg" ) {
  1751. Log3 $name, 5, "$name: sendmsg msg=$arg";
  1752. my ($protocol,$data,$repeats,$clock,$frequency) = split("#",$arg);
  1753. $protocol=~ s/[Pp](\d+)/$1/; # extract protocol num
  1754. $repeats=~ s/[rR](\d+)/$1/; # extract repeat num
  1755. $repeats=1 if (!defined($repeats));
  1756. if (defined($clock) && substr($clock,0,1) eq "F") { # wenn es kein clock gibt, pruefen ob im clock eine frequency ist
  1757. $clock=~ s/[F]([0-9a-fA-F]+$)/$1/;
  1758. $frequency = $clock;
  1759. $clock = undef;
  1760. } else {
  1761. $clock=~ s/[Cc](\d+)/$1/ if (defined($clock)); # extract ITClock num
  1762. $frequency=~ s/[Ff]([0-9a-fA-F]+$)/$1/ if (defined($frequency));
  1763. }
  1764. if (exists($ProtocolListSIGNALduino{$protocol}{frequency}) && $hasCC1101 && !defined($frequency)) {
  1765. $frequency = $ProtocolListSIGNALduino{$protocol}{frequency};
  1766. }
  1767. if (defined($frequency) && $hasCC1101) {
  1768. $frequency="F=$frequency;";
  1769. } else {
  1770. $frequency="";
  1771. }
  1772. return "$name: sendmsg, unknown protocol: $protocol" if (!exists($ProtocolListSIGNALduino{$protocol}));
  1773. #print ("data = $data \n");
  1774. #print ("protocol = $protocol \n");
  1775. #print ("repeats = $repeats \n");
  1776. my %signalHash;
  1777. my %patternHash;
  1778. my $pattern="";
  1779. my $cnt=0;
  1780. my $sendData;
  1781. if ($ProtocolListSIGNALduino{$protocol}{format} eq 'manchester')
  1782. {
  1783. #$clock = (map { $clock += $_ } @{$ProtocolListSIGNALduino{$protocol}{clockrange}}) / 2 if (!defined($clock));
  1784. $clock += $_ for(@{$ProtocolListSIGNALduino{$protocol}{clockrange}});
  1785. $clock = round($clock/2,0);
  1786. if ($protocol == 43) {
  1787. #$data =~ tr/0123456789ABCDEF/FEDCBA9876543210/;
  1788. }
  1789. my $intro = "";
  1790. my $outro = "";
  1791. $intro = $ProtocolListSIGNALduino{$protocol}{msgIntro} if ($ProtocolListSIGNALduino{$protocol}{msgIntro});
  1792. $outro = $ProtocolListSIGNALduino{$protocol}{msgOutro}.";" if ($ProtocolListSIGNALduino{$protocol}{msgOutro});
  1793. if ($intro ne "" || $outro ne "")
  1794. {
  1795. $intro = "SC;R=$repeats;" . $intro;
  1796. $repeats = 0;
  1797. }
  1798. $sendData = $intro . "SM;" . ($repeats > 0 ? "R=$repeats;" : "") . "C=$clock;D=$data;" . $outro . $frequency; # SM;R=2;C=400;D=AFAFAF;
  1799. Log3 $name, 5, "$name: sendmsg Preparing manchester protocol=$protocol, repeats=$repeats, clock=$clock data=$data";
  1800. } else {
  1801. if ($protocol == 3 || substr($data,0,2) eq "is") {
  1802. if (substr($data,0,2) eq "is") {
  1803. $data = substr($data,2); # is am Anfang entfernen
  1804. }
  1805. $data = SIGNALduino_ITV1_tristateToBit($data);
  1806. Log3 $name, 5, "$name: sendmsg IT V1 convertet tristate to bits=$data";
  1807. }
  1808. if (!defined($clock)) {
  1809. $hash->{ITClock} = 250 if (!defined($hash->{ITClock})); # Todo: Klaeren wo ITClock verwendet wird und ob wir diesen Teil nicht auf Protokoll 3,4 und 17 minimieren
  1810. $clock=$ProtocolListSIGNALduino{$protocol}{clockabs} > 1 ?$ProtocolListSIGNALduino{$protocol}{clockabs}:$hash->{ITClock};
  1811. }
  1812. Log3 $name, 5, "$name: sendmsg Preparing rawsend command for protocol=$protocol, repeats=$repeats, clock=$clock bits=$data";
  1813. foreach my $item (qw(sync start one zero float))
  1814. {
  1815. #print ("item= $item \n");
  1816. next if (!exists($ProtocolListSIGNALduino{$protocol}{$item}));
  1817. foreach my $p (@{$ProtocolListSIGNALduino{$protocol}{$item}})
  1818. {
  1819. #print (" p = $p \n");
  1820. if (!exists($patternHash{$p}))
  1821. {
  1822. $patternHash{$p}=$cnt;
  1823. $pattern.="P".$patternHash{$p}."=".$p*$clock.";";
  1824. $cnt++;
  1825. }
  1826. $signalHash{$item}.=$patternHash{$p};
  1827. #print (" signalHash{$item} = $signalHash{$item} \n");
  1828. }
  1829. }
  1830. my @bits = split("", $data);
  1831. my %bitconv = (1=>"one", 0=>"zero", 'D'=> "float");
  1832. my $SignalData="D=";
  1833. $SignalData.=$signalHash{sync} if (exists($signalHash{sync}));
  1834. $SignalData.=$signalHash{start} if (exists($signalHash{start}));
  1835. foreach my $bit (@bits)
  1836. {
  1837. next if (!exists($bitconv{$bit}));
  1838. #Log3 $name, 5, "encoding $bit";
  1839. $SignalData.=$signalHash{$bitconv{$bit}}; ## Add the signal to our data string
  1840. }
  1841. $sendData = "SR;R=$repeats;$pattern$SignalData;$frequency";
  1842. }
  1843. #SIGNALduino_SimpleWrite($hash, $sendData);
  1844. SIGNALduino_AddSendQueue($hash,$sendData);
  1845. Log3 $name, 4, "$name/set: sending via SendMsg: $sendData";
  1846. } else {
  1847. Log3 $name, 5, "$name/set: set $name $cmd $arg";
  1848. #SIGNALduino_SimpleWrite($hash, $arg);
  1849. return "Unknown argument $cmd, choose one of ". ReadingsVal($name,'cmd',' help me');
  1850. }
  1851. return undef;
  1852. }
  1853. #####################################
  1854. sub
  1855. SIGNALduino_Get($@)
  1856. {
  1857. my ($hash, @a) = @_;
  1858. my $type = $hash->{TYPE};
  1859. my $name = $hash->{NAME};
  1860. return "$name is not active, may firmware is not suppoted, please flash or reset" if (exists($hash->{DevState}) && $hash->{DevState} ne 'initialized');
  1861. #my $name = $a[0];
  1862. Log3 $name, 5, "\"get $type\" needs at least one parameter" if(@a < 2);
  1863. return "\"get $type\" needs at least one parameter" if(@a < 2);
  1864. if(!defined($gets{$a[1]})) {
  1865. my @cList = map { $_ =~ m/^(file|raw|ccreg)$/ ? $_ : "$_:noArg" } sort keys %gets;
  1866. return "Unknown argument $a[1], choose one of " . join(" ", @cList);
  1867. }
  1868. my $arg = ($a[2] ? $a[2] : "");
  1869. return "no command to send, get aborted." if (length($gets{$a[1]}[0]) == 0 && length($arg) == 0);
  1870. if (($a[1] eq "ccconf" || $a[1] eq "ccreg" || $a[1] eq "ccpatable") && $hash->{version} && $hash->{version} !~ m/cc1101/) {
  1871. return "This command is only available with a cc1101 receiver";
  1872. }
  1873. my ($msg, $err);
  1874. if (IsDummy($name))
  1875. {
  1876. if ($arg =~ /^M[CSU];.*/)
  1877. {
  1878. $arg="\002$arg\003"; ## Add start end end marker if not already there
  1879. Log3 $name, 5, "$name/msg adding start and endmarker to message";
  1880. }
  1881. if ($arg =~ /\002M.;.*;\003$/)
  1882. {
  1883. Log3 $name, 4, "$name/msg get raw: $arg";
  1884. return SIGNALduino_Parse($hash, $hash, $hash->{NAME}, $arg);
  1885. }
  1886. else {
  1887. my $arg2 = "";
  1888. if ($arg =~ m/^version=/) { # set version
  1889. $arg2 = substr($arg,8);
  1890. $hash->{version} = "V " . $arg2;
  1891. }
  1892. elsif ($arg =~ m/^regexp=/) { # set fileRegexp for get raw messages from file
  1893. $arg2 = substr($arg,7);
  1894. $hash->{fileRegexp} = $arg2;
  1895. delete($hash->{fileRegexp}) if (!$arg2);
  1896. }
  1897. elsif ($arg =~ m/^file=/) {
  1898. $arg2 = substr($arg,5);
  1899. my $n = 0;
  1900. if (open(my $fh, '<', $arg2)) {
  1901. my $fileRegexp = $hash->{fileRegexp};
  1902. while (my $row = <$fh>) {
  1903. if ($row =~ /.*\002M.;.*;\003$/) {
  1904. chomp $row;
  1905. $row =~ s/.*\002(M.;.*;)\003/$1/;
  1906. if (!defined($fileRegexp) || $row =~ m/$fileRegexp/) {
  1907. $n += 1;
  1908. $row="\002$row\003";
  1909. Log3 $name, 4, "$name/msg fileGetRaw: $row";
  1910. SIGNALduino_Parse($hash, $hash, $hash->{NAME}, $row);
  1911. }
  1912. }
  1913. }
  1914. return $n . " raw Nachrichten eingelesen";
  1915. } else {
  1916. return "Could not open file $arg2";
  1917. }
  1918. }
  1919. elsif ($arg eq '?') {
  1920. my $ret;
  1921. $ret = "dummy get raw\n\n";
  1922. $ret .= "raw message e.g. MS;P0=-392;P1=...\n";
  1923. $ret .= "dispatch message e.g. P7#6290DCF37\n";
  1924. $ret .= "version=x.x.x sets version. e.g. (version=3.2.0) to get old MC messages\n";
  1925. $ret .= "regexp= set fileRegexp for get raw messages from file. e.g. regexp=^MC\n";
  1926. $ret .= "file= gets raw messages from file in the fhem directory\n";
  1927. return $ret;
  1928. }
  1929. else {
  1930. Log3 $name, 4, "$name/msg get dispatch: $arg";
  1931. Dispatch($hash, $arg, undef);
  1932. }
  1933. return "";
  1934. }
  1935. }
  1936. return "No $a[1] for dummies" if(IsDummy($name));
  1937. Log3 $name, 5, "$name: command for gets: " . $gets{$a[1]}[0] . " " . $arg;
  1938. if ($a[1] eq "raw")
  1939. {
  1940. # Dirty hack to check and modify direct communication from logical modules with hardware
  1941. if ($arg =~ /^is.*/ && length($arg) == 34)
  1942. {
  1943. # Arctec protocol
  1944. Log3 $name, 5, "$name: calling set :sendmsg P17;R6#".substr($arg,2);
  1945. SIGNALduino_Set($hash,$name,"sendMsg","P17#",substr($arg,2),"#R6");
  1946. return "$a[0] $a[1] => $arg";
  1947. }
  1948. }
  1949. elsif ($a[1] eq "protocolIDs")
  1950. {
  1951. my $id;
  1952. my $ret;
  1953. my $s;
  1954. my $moduleId;
  1955. my @IdList = ();
  1956. foreach $id (keys %ProtocolListSIGNALduino)
  1957. {
  1958. next if ($id eq 'id');
  1959. push (@IdList, $id);
  1960. }
  1961. @IdList = sort { $a <=> $b } @IdList;
  1962. $ret = " ID modulname protocolname # comment\n\n";
  1963. foreach $id (@IdList)
  1964. {
  1965. $ret .= sprintf("%3s",$id) . " ";
  1966. if (exists ($ProtocolListSIGNALduino{$id}{format}) && $ProtocolListSIGNALduino{$id}{format} eq "manchester")
  1967. {
  1968. $ret .= "MC";
  1969. }
  1970. elsif (exists $ProtocolListSIGNALduino{$id}{sync})
  1971. {
  1972. $ret .= "MS";
  1973. }
  1974. elsif (exists ($ProtocolListSIGNALduino{$id}{clockabs}))
  1975. {
  1976. $ret .= "MU";
  1977. }
  1978. if (exists ($ProtocolListSIGNALduino{$id}{clientmodule}))
  1979. {
  1980. $moduleId .= "$id,";
  1981. $s = $ProtocolListSIGNALduino{$id}{clientmodule};
  1982. if (length($s) < 15)
  1983. {
  1984. $s .= substr(" ",length($s) - 15);
  1985. }
  1986. $ret .= " $s";
  1987. }
  1988. else
  1989. {
  1990. $ret .= " ";
  1991. }
  1992. if (exists ($ProtocolListSIGNALduino{$id}{name}))
  1993. {
  1994. $ret .= " $ProtocolListSIGNALduino{$id}{name}";
  1995. }
  1996. if (exists ($ProtocolListSIGNALduino{$id}{comment}))
  1997. {
  1998. $ret .= " # $ProtocolListSIGNALduino{$id}{comment}";
  1999. }
  2000. $ret .= "\n";
  2001. }
  2002. #$moduleId =~ s/,$//;
  2003. return "$a[1]: \n\n$ret\n";
  2004. #return "$a[1]: \n\n$ret\nIds with modules: $moduleId";
  2005. }
  2006. #SIGNALduino_SimpleWrite($hash, $gets{$a[1]}[0] . $arg);
  2007. SIGNALduino_AddSendQueue($hash, $gets{$a[1]}[0] . $arg);
  2008. $hash->{getcmd}->{cmd}=$a[1];
  2009. $hash->{getcmd}->{asyncOut}=$hash->{CL};
  2010. $hash->{getcmd}->{timenow}=time();
  2011. return undef; # We will exit here, and give an output only, if asny output is supported. If this is not supported, only the readings are updated
  2012. }
  2013. sub SIGNALduino_parseResponse($$$)
  2014. {
  2015. my $hash = shift;
  2016. my $cmd = shift;
  2017. my $msg = shift;
  2018. my $name=$hash->{NAME};
  2019. $msg =~ s/[\r\n]//g;
  2020. if($cmd eq "cmds")
  2021. { # nice it up
  2022. $msg =~ s/$name cmds =>//g;
  2023. $msg =~ s/.*Use one of//g;
  2024. }
  2025. elsif($cmd eq "uptime")
  2026. { # decode it
  2027. #$msg = hex($msg); # /125; only for col or coc
  2028. $msg = sprintf("%d %02d:%02d:%02d", $msg/86400, ($msg%86400)/3600, ($msg%3600)/60, $msg%60);
  2029. }
  2030. elsif($cmd eq "ccregAll")
  2031. {
  2032. $msg =~ s/ /\n/g;
  2033. $msg = "\n\n" . $msg
  2034. }
  2035. elsif($cmd eq "ccconf")
  2036. {
  2037. my (undef,$str) = split('=', $msg);
  2038. my $var;
  2039. my %r = ( "0D"=>1,"0E"=>1,"0F"=>1,"10"=>1,"11"=>1,"1B"=>1,"1D"=>1 );
  2040. $msg = "";
  2041. foreach my $a (sort keys %r) {
  2042. $var = substr($str,(hex($a)-13)*2, 2);
  2043. $r{$a} = hex($var);
  2044. }
  2045. $msg = sprintf("freq:%.3fMHz bWidth:%dKHz rAmpl:%ddB sens:%ddB (DataRate:%.2fBaud)",
  2046. 26*(($r{"0D"}*256+$r{"0E"})*256+$r{"0F"})/65536, #Freq
  2047. 26000/(8 * (4+(($r{"10"}>>4)&3)) * (1 << (($r{"10"}>>6)&3))), #Bw
  2048. $ampllist[$r{"1B"}&7], #rAmpl
  2049. 4+4*($r{"1D"}&3), #Sens
  2050. ((256+$r{"11"})*(2**($r{"10"} & 15 )))*26000000/(2**28) #DataRate
  2051. );
  2052. }
  2053. elsif($cmd eq "bWidth") {
  2054. my $val = hex(substr($msg,6));
  2055. my $arg = $hash->{getcmd}->{arg};
  2056. my $ob = $val & 0x0f;
  2057. my ($bits, $bw) = (0,0);
  2058. OUTERLOOP:
  2059. for (my $e = 0; $e < 4; $e++) {
  2060. for (my $m = 0; $m < 4; $m++) {
  2061. $bits = ($e<<6)+($m<<4);
  2062. $bw = int(26000/(8 * (4+$m) * (1 << $e))); # KHz
  2063. last OUTERLOOP if($arg >= $bw);
  2064. }
  2065. }
  2066. $ob = sprintf("%02x", $ob+$bits);
  2067. $msg = "Setting MDMCFG4 (10) to $ob = $bw KHz";
  2068. Log3 $name, 3, "$name/msg parseResponse bWidth: Setting MDMCFG4 (10) to $ob = $bw KHz";
  2069. delete($hash->{getcmd});
  2070. SIGNALduino_AddSendQueue($hash,"W12$ob");
  2071. SIGNALduino_WriteInit($hash);
  2072. }
  2073. elsif($cmd eq "ccpatable") {
  2074. my $CC1101Frequency = "433";
  2075. if (defined($hash->{cc1101_frequency})) {
  2076. $CC1101Frequency = $hash->{cc1101_frequency};
  2077. }
  2078. my $dBn = substr($msg,9,2);
  2079. Log3 $name, 3, "$name/msg parseResponse patable: $dBn";
  2080. foreach my $dB (keys %{ $patable{$CC1101Frequency} }) {
  2081. if ($dBn eq $patable{$CC1101Frequency}{$dB}) {
  2082. Log3 $name, 5, "$name/msg parseResponse patable: $dB";
  2083. $msg .= " => $dB";
  2084. last;
  2085. }
  2086. }
  2087. # $msg .= "\n\n$CC1101Frequency MHz\n\n";
  2088. # foreach my $dB (keys $patable{$CC1101Frequency})
  2089. # {
  2090. # $msg .= "$patable{$CC1101Frequency}{$dB} $dB\n";
  2091. # }
  2092. }
  2093. return $msg;
  2094. }
  2095. #####################################
  2096. sub
  2097. SIGNALduino_ResetDevice($)
  2098. {
  2099. my ($hash) = @_;
  2100. my $name = $hash->{NAME};
  2101. Log3 $hash, 3, "$name reset";
  2102. DevIo_CloseDev($hash);
  2103. my $ret = DevIo_OpenDev($hash, 0, "SIGNALduino_DoInit", 'SIGNALduino_Connect');
  2104. return $ret;
  2105. }
  2106. #####################################
  2107. sub
  2108. SIGNALduino_CloseDevice($)
  2109. {
  2110. my ($hash) = @_;
  2111. my $name = $hash->{NAME};
  2112. Log3 $hash, 2, "$name closed";
  2113. RemoveInternalTimer($hash);
  2114. DevIo_CloseDev($hash);
  2115. readingsSingleUpdate($hash, "state", "closed", 1);
  2116. return undef;
  2117. }
  2118. #####################################
  2119. sub
  2120. SIGNALduino_DoInit($)
  2121. {
  2122. my $hash = shift;
  2123. my $name = $hash->{NAME};
  2124. my $err;
  2125. my $msg = undef;
  2126. my ($ver, $try) = ("", 0);
  2127. #Dirty hack to allow initialisation of DirectIO Device for some debugging and tesing
  2128. Log3 $hash, 1, "$name/define: ".$hash->{DEF};
  2129. delete($hash->{disConnFlag}) if defined($hash->{disConnFlag});
  2130. RemoveInternalTimer("HandleWriteQueue:$name");
  2131. @{$hash->{QUEUE}} = ();
  2132. $hash->{sendworking} = 0;
  2133. # if (($hash->{DEF} !~ m/\@DirectIO/) and ($hash->{DEF} !~ m/none/) )
  2134. if (($hash->{DEF} !~ m/\@directio/) and ($hash->{DEF} !~ m/none/) )
  2135. {
  2136. Log3 $hash, 1, "$name/init: ".$hash->{DEF};
  2137. $hash->{initretry} = 0;
  2138. RemoveInternalTimer($hash);
  2139. #SIGNALduino_SimpleWrite($hash, "XQ"); # Disable receiver
  2140. InternalTimer(gettimeofday() + SDUINO_INIT_WAIT_XQ, "SIGNALduino_SimpleWrite_XQ", $hash, 0);
  2141. InternalTimer(gettimeofday() + SDUINO_INIT_WAIT, "SIGNALduino_StartInit", $hash, 0);
  2142. }
  2143. # Reset the counter
  2144. delete($hash->{XMIT_TIME});
  2145. delete($hash->{NR_CMD_LAST_H});
  2146. return;
  2147. return undef;
  2148. }
  2149. # Disable receiver
  2150. sub SIGNALduino_SimpleWrite_XQ($) {
  2151. my ($hash) = @_;
  2152. my $name = $hash->{NAME};
  2153. Log3 $hash, 3, "$name/init: disable receiver (XQ)";
  2154. SIGNALduino_SimpleWrite($hash, "XQ");
  2155. #DevIo_SimpleWrite($hash, "XQ\n",2);
  2156. }
  2157. sub SIGNALduino_StartInit($)
  2158. {
  2159. my ($hash) = @_;
  2160. my $name = $hash->{NAME};
  2161. $hash->{version} = undef;
  2162. Log3 $name,3 , "$name/init: get version, retry = " . $hash->{initretry};
  2163. if ($hash->{initretry} >= SDUINO_INIT_MAXRETRY) {
  2164. $hash->{DevState} = 'INACTIVE';
  2165. # einmaliger reset, wenn danach immer noch 'init retry count reached', dann SIGNALduino_CloseDevice()
  2166. if (!defined($hash->{initResetFlag})) {
  2167. Log3 $name,2 , "$name/init retry count reached. Reset";
  2168. $hash->{initResetFlag} = 1;
  2169. SIGNALduino_ResetDevice($hash);
  2170. } else {
  2171. Log3 $name,2 , "$name/init retry count reached. Closed";
  2172. SIGNALduino_CloseDevice($hash);
  2173. }
  2174. return;
  2175. }
  2176. else {
  2177. $hash->{getcmd}->{cmd} = "version";
  2178. SIGNALduino_SimpleWrite($hash, "V");
  2179. #DevIo_SimpleWrite($hash, "V\n",2);
  2180. $hash->{DevState} = 'waitInit';
  2181. RemoveInternalTimer($hash);
  2182. InternalTimer(gettimeofday() + SDUINO_CMD_TIMEOUT, "SIGNALduino_CheckCmdResp", $hash, 0);
  2183. }
  2184. }
  2185. ####################
  2186. sub SIGNALduino_CheckCmdResp($)
  2187. {
  2188. my ($hash) = @_;
  2189. my $name = $hash->{NAME};
  2190. my $msg = undef;
  2191. my $ver;
  2192. if ($hash->{version}) {
  2193. $ver = $hash->{version};
  2194. if ($ver !~ m/SIGNAL(duino|ESP)/) {
  2195. $msg = "$name: Not an SIGNALduino device, setting attribute dummy=1 got for V: $ver";
  2196. Log3 $hash, 1, $msg;
  2197. readingsSingleUpdate($hash, "state", "no SIGNALduino found", 1);
  2198. $hash->{DevState} = 'INACTIVE';
  2199. SIGNALduino_CloseDevice($hash);
  2200. }
  2201. elsif($ver =~ m/^V 3\.1\./) {
  2202. $msg = "$name: Version of your arduino is not compatible, pleas flash new firmware. (device closed) Got for V: $ver";
  2203. readingsSingleUpdate($hash, "state", "unsupported firmware found", 1);
  2204. Log3 $hash, 1, $msg;
  2205. $hash->{DevState} = 'INACTIVE';
  2206. SIGNALduino_CloseDevice($hash);
  2207. }
  2208. else {
  2209. readingsSingleUpdate($hash, "state", "opened", 1);
  2210. Log3 $name, 2, "$name: initialized. " . SDUINO_VERSION;
  2211. $hash->{DevState} = 'initialized';
  2212. delete($hash->{initResetFlag}) if defined($hash->{initResetFlag});
  2213. SIGNALduino_SimpleWrite($hash, "XE"); # Enable receiver
  2214. #DevIo_SimpleWrite($hash, "XE\n",2);
  2215. Log3 $hash, 3, "$name/init: enable receiver (XE)";
  2216. delete($hash->{initretry});
  2217. # initialize keepalive
  2218. $hash->{keepalive}{ok} = 0;
  2219. $hash->{keepalive}{retry} = 0;
  2220. InternalTimer(gettimeofday() + SDUINO_KEEPALIVE_TIMEOUT, "SIGNALduino_KeepAlive", $hash, 0);
  2221. }
  2222. }
  2223. else {
  2224. delete($hash->{getcmd});
  2225. $hash->{initretry} ++;
  2226. #InternalTimer(gettimeofday()+1, "SIGNALduino_StartInit", $hash, 0);
  2227. SIGNALduino_StartInit($hash);
  2228. }
  2229. }
  2230. #####################################
  2231. # Check if the 1% limit is reached and trigger notifies
  2232. sub
  2233. SIGNALduino_XmitLimitCheck($$)
  2234. {
  2235. my ($hash,$fn) = @_;
  2236. return if ($fn !~ m/^(is|SR).*/);
  2237. my $now = time();
  2238. if(!$hash->{XMIT_TIME}) {
  2239. $hash->{XMIT_TIME}[0] = $now;
  2240. $hash->{NR_CMD_LAST_H} = 1;
  2241. return;
  2242. }
  2243. my $nowM1h = $now-3600;
  2244. my @b = grep { $_ > $nowM1h } @{$hash->{XMIT_TIME}};
  2245. if(@b > 163) { # Maximum nr of transmissions per hour (unconfirmed).
  2246. my $name = $hash->{NAME};
  2247. Log3 $name, 2, "SIGNALduino TRANSMIT LIMIT EXCEEDED";
  2248. DoTrigger($name, "TRANSMIT LIMIT EXCEEDED");
  2249. } else {
  2250. push(@b, $now);
  2251. }
  2252. $hash->{XMIT_TIME} = \@b;
  2253. $hash->{NR_CMD_LAST_H} = int(@b);
  2254. }
  2255. #####################################
  2256. ## API to logical modules: Provide as Hash of IO Device, type of function ; command to call ; message to send
  2257. sub
  2258. SIGNALduino_Write($$$)
  2259. {
  2260. my ($hash,$fn,$msg) = @_;
  2261. my $name = $hash->{NAME};
  2262. $fn="RAW" if $fn eq "";
  2263. Log3 $name, 5, "$name/write: adding to queue $fn $msg";
  2264. #SIGNALduino_SimpleWrite($hash, $bstring);
  2265. SIGNALduino_Set($hash,$name,$fn,$msg);
  2266. #SIGNALduino_AddSendQueue($hash,$bstring);
  2267. }
  2268. sub SIGNALduino_AddSendQueue($$)
  2269. {
  2270. my ($hash, $msg) = @_;
  2271. my $name = $hash->{NAME};
  2272. push(@{$hash->{QUEUE}}, $msg);
  2273. #Log3 $hash , 5, Dumper($hash->{QUEUE});
  2274. Log3 $hash, 5,"AddSendQueue: " . $hash->{NAME} . ": $msg (" . @{$hash->{QUEUE}} . ")";
  2275. InternalTimer(gettimeofday() + 0.1, "SIGNALduino_HandleWriteQueue", "HandleWriteQueue:$name") if (@{$hash->{QUEUE}} == 1 && $hash->{sendworking} == 0);
  2276. }
  2277. sub
  2278. SIGNALduino_SendFromQueue($$)
  2279. {
  2280. my ($hash, $msg) = @_;
  2281. my $name = $hash->{NAME};
  2282. if($msg ne "") {
  2283. SIGNALduino_XmitLimitCheck($hash,$msg);
  2284. #DevIo_SimpleWrite($hash, $msg . "\n", 2);
  2285. $hash->{sendworking} = 1;
  2286. SIGNALduino_SimpleWrite($hash,$msg);
  2287. if ($msg =~ m/^S(R|C|M);/) {
  2288. $hash->{getcmd}->{cmd} = 'sendraw';
  2289. Log3 $hash, 4, "$name SendrawFromQueue: msg=$msg"; # zu testen der Queue, kann wenn es funktioniert auskommentiert werden
  2290. }
  2291. elsif ($msg eq "C99") {
  2292. $hash->{getcmd}->{cmd} = 'ccregAll';
  2293. }
  2294. }
  2295. ##############
  2296. # Write the next buffer not earlier than 0.23 seconds
  2297. # else it will be sent too early by the SIGNALduino, resulting in a collision, or may the last command is not finished
  2298. if (defined($hash->{getcmd}->{cmd}) && $hash->{getcmd}->{cmd} eq 'sendraw') {
  2299. InternalTimer(gettimeofday() + SDUINO_WRITEQUEUE_TIMEOUT, "SIGNALduino_HandleWriteQueue", "HandleWriteQueue:$name");
  2300. } else {
  2301. InternalTimer(gettimeofday() + SDUINO_WRITEQUEUE_NEXT, "SIGNALduino_HandleWriteQueue", "HandleWriteQueue:$name");
  2302. }
  2303. }
  2304. ####################################
  2305. sub
  2306. SIGNALduino_HandleWriteQueue($)
  2307. {
  2308. my($param) = @_;
  2309. my(undef,$name) = split(':', $param);
  2310. my $hash = $defs{$name};
  2311. #my @arr = @{$hash->{QUEUE}};
  2312. $hash->{sendworking} = 0; # es wurde gesendet
  2313. if (defined($hash->{getcmd}->{cmd}) && $hash->{getcmd}->{cmd} eq 'sendraw') {
  2314. Log3 $name, 4, "$name/HandleWriteQueue: sendraw no answer (timeout)";
  2315. delete($hash->{getcmd});
  2316. }
  2317. if(@{$hash->{QUEUE}}) {
  2318. my $msg= shift(@{$hash->{QUEUE}});
  2319. if($msg eq "") {
  2320. SIGNALduino_HandleWriteQueue("x:$name");
  2321. } else {
  2322. SIGNALduino_SendFromQueue($hash, $msg);
  2323. }
  2324. } else {
  2325. Log3 $name, 4, "$name/HandleWriteQueue: nothing to send, stopping timer";
  2326. RemoveInternalTimer("HandleWriteQueue:$name");
  2327. }
  2328. }
  2329. #####################################
  2330. # called from the global loop, when the select for hash->{FD} reports data
  2331. sub
  2332. SIGNALduino_Read($)
  2333. {
  2334. my ($hash) = @_;
  2335. my $buf = DevIo_SimpleRead($hash);
  2336. return "" if(!defined($buf));
  2337. my $name = $hash->{NAME};
  2338. my $debug = AttrVal($name,"debug",0);
  2339. my $SIGNALduinodata = $hash->{PARTIAL};
  2340. Log3 $name, 5, "$name/RAW READ: $SIGNALduinodata/$buf" if ($debug);
  2341. $SIGNALduinodata .= $buf;
  2342. while($SIGNALduinodata =~ m/\n/) {
  2343. my $rmsg;
  2344. ($rmsg,$SIGNALduinodata) = split("\n", $SIGNALduinodata, 2);
  2345. $rmsg =~ s/\r//;
  2346. if ($rmsg =~ m/^\002(M(s|u);.*;)\003/) {
  2347. $rmsg =~ s/^\002//; # \002 am Anfang entfernen
  2348. my @msg_parts = split(";",$rmsg);
  2349. my $m0;
  2350. my $mnr0;
  2351. my $m1;
  2352. my $mL;
  2353. my $mH;
  2354. my $part = "";
  2355. my $partD;
  2356. foreach my $msgPart (@msg_parts) {
  2357. $m0 = substr($msgPart,0,1);
  2358. $mnr0 = ord($m0);
  2359. $m1 = substr($msgPart,1);
  2360. if ($m0 eq "M") {
  2361. $part .= "M" . uc($m1) . ";";
  2362. }
  2363. elsif ($mnr0 > 127) {
  2364. $part .= "P" . sprintf("%u", ($mnr0 & 7)) . "=";
  2365. if (length($m1) == 2) {
  2366. $mL = ord(substr($m1,0,1)) & 127; # Pattern low
  2367. $mH = ord(substr($m1,1,1)) & 127; # Pattern high
  2368. if (($mnr0 & 0b00100000) != 0) { # Vorzeichen 0b00100000 = 32
  2369. $part .= "-";
  2370. }
  2371. if ($mnr0 & 0b00010000) { # Bit 7 von Pattern low
  2372. $mL += 128;
  2373. }
  2374. $part .= ($mH * 256) + $mL;
  2375. }
  2376. $part .= ";";
  2377. }
  2378. elsif (($m0 eq "D" || $m0 eq "d") && length($m1) > 0) {
  2379. my @arrayD = split(//, $m1);
  2380. $part .= "D=";
  2381. $partD = "";
  2382. foreach my $D (@arrayD) {
  2383. $mH = ord($D) >> 4;
  2384. $mL = ord($D) & 7;
  2385. $partD .= "$mH$mL";
  2386. }
  2387. #Log3 $name, 3, "$name/msg READredu1$m0: $partD";
  2388. if ($m0 eq "d") {
  2389. $partD =~ s/.$//; # letzte Ziffer entfernen wenn Anzahl der Ziffern ungerade
  2390. }
  2391. $partD =~ s/^8//; # 8 am Anfang entfernen
  2392. #Log3 $name, 3, "$name/msg READredu2$m0: $partD";
  2393. $part = $part . $partD . ';';
  2394. }
  2395. elsif (($m0 eq "C" || $m0 eq "S") && length($m1) == 1) {
  2396. $part .= "$m0" . "P=$m1;";
  2397. }
  2398. elsif ($m1 =~ m/^[0-9A-Z]{1,2}$/) { # bei 1 oder 2 Hex Ziffern nach Dez wandeln
  2399. $part .= "$m0=" . hex($m1) . ";";
  2400. }
  2401. elsif ($m0 =~m/[0-9a-zA-Z]/) {
  2402. $part .= "$m0";
  2403. if ($m1 ne "") {
  2404. $part .= "=$m1";
  2405. }
  2406. $part .= ";";
  2407. }
  2408. }
  2409. Log3 $name, 4, "$name/msg READredu: $part";
  2410. $rmsg = "\002$part\003";
  2411. }
  2412. else {
  2413. Log3 $name, 4, "$name/msg READ: $rmsg";
  2414. }
  2415. if ( $rmsg && !SIGNALduino_Parse($hash, $hash, $name, $rmsg) && defined($hash->{getcmd}) && defined($hash->{getcmd}->{cmd}))
  2416. {
  2417. my $regexp;
  2418. if ($hash->{getcmd}->{cmd} eq 'sendraw') {
  2419. $regexp = '^S(R|C|M);';
  2420. }
  2421. elsif ($hash->{getcmd}->{cmd} eq 'ccregAll') {
  2422. $regexp = '^ccreg 00:';
  2423. }
  2424. elsif ($hash->{getcmd}->{cmd} eq 'bWidth') {
  2425. $regexp = '^C.* = .*';
  2426. }
  2427. else {
  2428. $regexp = $gets{$hash->{getcmd}->{cmd}}[1];
  2429. }
  2430. if(!defined($regexp) || $rmsg =~ m/$regexp/) {
  2431. if (defined($hash->{keepalive})) {
  2432. $hash->{keepalive}{ok} = 1;
  2433. $hash->{keepalive}{retry} = 0;
  2434. }
  2435. Log3 $name, 5, "$name/msg READ: regexp=$regexp cmd=$hash->{getcmd}->{cmd} msg=$rmsg";
  2436. if ($hash->{getcmd}->{cmd} eq 'version') {
  2437. my $msg_start = index($rmsg, 'V 3.');
  2438. if ($msg_start > 0) {
  2439. $rmsg = substr($rmsg, $msg_start);
  2440. Log3 $name, 4, "$name/read: cut chars at begin. msgstart = $msg_start msg = $rmsg";
  2441. }
  2442. $hash->{version} = $rmsg;
  2443. if (defined($hash->{DevState}) && $hash->{DevState} eq 'waitInit') {
  2444. RemoveInternalTimer($hash);
  2445. SIGNALduino_CheckCmdResp($hash);
  2446. }
  2447. }
  2448. if ($hash->{getcmd}->{cmd} eq 'sendraw') {
  2449. # zu testen der sendeQueue, kann wenn es funktioniert auf verbose 5
  2450. Log3 $name, 4, "$name/read sendraw answer: $rmsg";
  2451. delete($hash->{getcmd});
  2452. RemoveInternalTimer("HandleWriteQueue:$name");
  2453. SIGNALduino_HandleWriteQueue("x:$name");
  2454. }
  2455. else {
  2456. $rmsg = SIGNALduino_parseResponse($hash,$hash->{getcmd}->{cmd},$rmsg);
  2457. if (defined($hash->{getcmd}) && $hash->{getcmd}->{cmd} ne 'ccregAll') {
  2458. readingsSingleUpdate($hash, $hash->{getcmd}->{cmd}, $rmsg, 0);
  2459. }
  2460. if (defined($hash->{getcmd}->{asyncOut})) {
  2461. #Log3 $name, 4, "$name/msg READ: asyncOutput";
  2462. my $ao = asyncOutput( $hash->{getcmd}->{asyncOut}, $hash->{getcmd}->{cmd}.": " . $rmsg );
  2463. }
  2464. delete($hash->{getcmd});
  2465. }
  2466. } else {
  2467. Log3 $name, 4, "$name/msg READ: Received answer ($rmsg) for ". $hash->{getcmd}->{cmd}." does not match $regexp";
  2468. }
  2469. }
  2470. }
  2471. $hash->{PARTIAL} = $SIGNALduinodata;
  2472. }
  2473. sub SIGNALduino_KeepAlive($){
  2474. my ($hash) = @_;
  2475. my $name = $hash->{NAME};
  2476. return if ($hash->{DevState} eq 'disconnected');
  2477. #Log3 $name,4 , "$name/KeepAliveOk: " . $hash->{keepalive}{ok};
  2478. if (!$hash->{keepalive}{ok}) {
  2479. delete($hash->{getcmd});
  2480. if ($hash->{keepalive}{retry} >= SDUINO_KEEPALIVE_MAXRETRY) {
  2481. Log3 $name,3 , "$name/keepalive not ok, retry count reached. Reset";
  2482. $hash->{DevState} = 'INACTIVE';
  2483. SIGNALduino_ResetDevice($hash);
  2484. return;
  2485. }
  2486. else {
  2487. my $logLevel = 3;
  2488. $hash->{keepalive}{retry} ++;
  2489. if ($hash->{keepalive}{retry} == 1) {
  2490. $logLevel = 4;
  2491. }
  2492. Log3 $name, $logLevel, "$name/KeepAlive not ok, retry = " . $hash->{keepalive}{retry} . " -> get ping";
  2493. $hash->{getcmd}->{cmd} = "ping";
  2494. SIGNALduino_AddSendQueue($hash, "P");
  2495. #SIGNALduino_SimpleWrite($hash, "P");
  2496. }
  2497. }
  2498. else {
  2499. Log3 $name,4 , "$name/keepalive ok, retry = " . $hash->{keepalive}{retry};
  2500. }
  2501. $hash->{keepalive}{ok} = 0;
  2502. InternalTimer(gettimeofday() + SDUINO_KEEPALIVE_TIMEOUT, "SIGNALduino_KeepAlive", $hash);
  2503. }
  2504. ### Helper Subs >>>
  2505. ## Parses a HTTP Response for example for flash via http download
  2506. sub SIGNALduino_ParseHttpResponse
  2507. {
  2508. my ($param, $err, $data) = @_;
  2509. my $hash = $param->{hash};
  2510. my $name = $hash->{NAME};
  2511. if($err ne "") # wenn ein Fehler bei der HTTP Abfrage aufgetreten ist
  2512. {
  2513. Log3 $name, 3, "error while requesting ".$param->{url}." - $err"; # Eintrag fürs Log
  2514. }
  2515. elsif($param->{code} eq "200" && $data ne "") # wenn die Abfrage erfolgreich war ($data enthält die Ergebnisdaten des HTTP Aufrufes)
  2516. {
  2517. Log3 $name, 3, "url ".$param->{url}." returned: ".length($data)." bytes Data"; # Eintrag fürs Log
  2518. if ($param->{command} eq "flash")
  2519. {
  2520. my $filename;
  2521. if ($param->{httpheader} =~ /Content-Disposition: attachment;.?filename=\"?([-+.\w]+)?\"?/)
  2522. {
  2523. $filename = $1;
  2524. } else { # Filename via path if not specifyied via Content-Disposition
  2525. ($filename = $param->{path}) =~s/.*\///;
  2526. }
  2527. Log3 $name, 3, "$name: Downloaded $filename firmware from ".$param->{host};
  2528. Log3 $name, 5, "$name: Header = ".$param->{httpheader};
  2529. $filename = "FHEM/firmware/" . $filename;
  2530. open(my $file, ">", $filename) or die $!;
  2531. print $file $data;
  2532. close $file;
  2533. # Den Flash Befehl mit der soebene heruntergeladenen Datei ausführen
  2534. #Log3 $name, 3, "calling set ".$param->{command}." $filename"; # Eintrag fürs Log
  2535. SIGNALduino_Set($hash,$name,$param->{command},$filename); # $hash->{SetFn}
  2536. }
  2537. } else {
  2538. Log3 $name, 3, "undefined error while requesting ".$param->{url}." - $err - code=".$param->{code}; # Eintrag fürs Log
  2539. }
  2540. }
  2541. sub SIGNALduino_splitMsg
  2542. {
  2543. my $txt = shift;
  2544. my $delim = shift;
  2545. my @msg_parts = split(/$delim/,$txt);
  2546. return @msg_parts;
  2547. }
  2548. # $value - $set <= $tolerance
  2549. sub SIGNALduino_inTol($$$)
  2550. {
  2551. #Debug "sduino abs \($_[0] - $_[1]\) <= $_[2] ";
  2552. return (abs($_[0]-$_[1])<=$_[2]);
  2553. }
  2554. # - - - - - - - - - - - -
  2555. #=item SIGNALduino_PatternExists()
  2556. #This functons, needs reference to $hash, @array of values to search and %patternList where to find the matches.
  2557. #
  2558. # Will return -1 if pattern is not found or a string, containing the indexes which are in tolerance and have the smallest gap to what we searched
  2559. # =cut
  2560. # 01232323242423 while ($message =~ /$pstr/g) { $count++ }
  2561. sub SIGNALduino_PatternExists
  2562. {
  2563. my ($hash,$search,$patternList,$data) = @_;
  2564. #my %patternList=$arg3;
  2565. #Debug "plist: ".Dumper($patternList) if($debug);
  2566. #Debug "searchlist: ".Dumper($search) if($debug);
  2567. my $searchpattern;
  2568. my $valid=1;
  2569. my @pstr;
  2570. my $debug = AttrVal($hash->{NAME},"debug",0);
  2571. my $i=0;
  2572. my $maxcol=0;
  2573. foreach $searchpattern (@{$search}) # z.B. [1, -4]
  2574. {
  2575. #my $patt_id;
  2576. # Calculate tolernace for search
  2577. #my $tol=abs(abs($searchpattern)>=2 ?$searchpattern*0.3:$searchpattern*1.5);
  2578. my $tol=abs(abs($searchpattern)>3 ? abs($searchpattern)>16 ? $searchpattern*0.18 : $searchpattern*0.3 : 1); #tol is minimum 1 or higer, depending on our searched pulselengh
  2579. Debug "tol: looking for ($searchpattern +- $tol)" if($debug);
  2580. my %pattern_gap ; #= {};
  2581. # Find and store the gap of every pattern, which is in tolerance
  2582. %pattern_gap = map { $_ => abs($patternList->{$_}-$searchpattern) } grep { abs($patternList->{$_}-$searchpattern) <= $tol} (keys %$patternList);
  2583. if (scalar keys %pattern_gap > 0)
  2584. {
  2585. Debug "index => gap in tol (+- $tol) of pulse ($searchpattern) : ".Dumper(\%pattern_gap) if($debug);
  2586. # Extract fist pattern, which is nearst to our searched value
  2587. my @closestidx = (sort {$pattern_gap{$a} <=> $pattern_gap{$b}} keys %pattern_gap);
  2588. my $idxstr="";
  2589. my $r=0;
  2590. while (my ($item) = splice(@closestidx, 0, 1))
  2591. {
  2592. $pstr[$i][$r]=$item;
  2593. $r++;
  2594. Debug "closest pattern has index: $item" if($debug);
  2595. }
  2596. $valid=1;
  2597. } else {
  2598. # search is not found, return -1
  2599. return -1;
  2600. last;
  2601. }
  2602. $i++;
  2603. #return ($valid ? $pstr : -1); # return $pstr if $valid or -1
  2604. #foreach $patt_id (keys %$patternList) {
  2605. #Debug "$patt_id. chk ->intol $patternList->{$patt_id} $searchpattern $tol";
  2606. #$valid = SIGNALduino_inTol($patternList->{$patt_id}, $searchpattern, $tol);
  2607. #if ( $valid) #one pulse found in tolerance, search next one
  2608. #{
  2609. # $pstr="$pstr$patt_id";
  2610. # # provide this index for further lookup table -> {$patt_id = $searchpattern}
  2611. # Debug "pulse found";
  2612. # last ; ## Exit foreach loop if searched pattern matches pattern in list
  2613. #}
  2614. #}
  2615. #last if (!$valid); ## Exit loop if a complete iteration has not found anything
  2616. }
  2617. my @results = ('');
  2618. foreach my $subarray (@pstr)
  2619. {
  2620. @results = map {my $res = $_; map $res.$_, @$subarray } @results;
  2621. }
  2622. foreach my $search (@results)
  2623. {
  2624. Debug "looking for substr $search" if($debug);
  2625. return $search if (index( ${$data}, $search) >= 0);
  2626. }
  2627. return -1;
  2628. #return ($valid ? @results : -1); # return @pstr if $valid or -1
  2629. }
  2630. #SIGNALduino_MatchSignalPattern{$hash,@array, %hash, @array, $scalar}; not used >v3.1.3
  2631. sub SIGNALduino_MatchSignalPattern($\@\%\@$){
  2632. my ( $hash, $signalpattern, $patternList, $data_array, $idx) = @_;
  2633. my $name = $hash->{NAME};
  2634. #print Dumper($patternList);
  2635. #print Dumper($idx);
  2636. #Debug Dumper($signalpattern) if ($debug);
  2637. my $tol="0.2"; # Tolerance factor
  2638. my $found=0;
  2639. my $debug = AttrVal($hash->{NAME},"debug",0);
  2640. foreach ( @{$signalpattern} )
  2641. {
  2642. #Debug " $idx check: ".$patternList->{$data_array->[$idx]}." == ".$_;
  2643. Debug "$name: idx: $idx check: abs(". $patternList->{$data_array->[$idx]}." - ".$_.") > ". ceil(abs($patternList->{$data_array->[$idx]}*$tol)) if ($debug);
  2644. #print "\n";;
  2645. #if ($patternList->{$data_array->[$idx]} ne $_ )
  2646. ### Nachkommastelle von ceil!!!
  2647. if (!defined( $patternList->{$data_array->[$idx]})){
  2648. Debug "$name: Error index ($idx) does not exist!!" if ($debug);
  2649. return -1;
  2650. }
  2651. if (abs($patternList->{$data_array->[$idx]} - $_) > ceil(abs($patternList->{$data_array->[$idx]}*$tol)))
  2652. {
  2653. return -1; ## Pattern does not match, return -1 = not matched
  2654. }
  2655. $found=1;
  2656. $idx++;
  2657. }
  2658. if ($found)
  2659. {
  2660. return $idx; ## Return new Index Position
  2661. }
  2662. }
  2663. sub SIGNALduino_b2h {
  2664. my $num = shift;
  2665. my $WIDTH = 4;
  2666. my $index = length($num) - $WIDTH;
  2667. my $hex = '';
  2668. do {
  2669. my $width = $WIDTH;
  2670. if ($index < 0) {
  2671. $width += $index;
  2672. $index = 0;
  2673. }
  2674. my $cut_string = substr($num, $index, $width);
  2675. $hex = sprintf('%X', oct("0b$cut_string")) . $hex;
  2676. $index -= $WIDTH;
  2677. } while ($index > (-1 * $WIDTH));
  2678. return $hex;
  2679. }
  2680. sub SIGNALduino_Split_Message($$)
  2681. {
  2682. my $rmsg = shift;
  2683. my $name = shift;
  2684. my %patternList;
  2685. my $clockidx;
  2686. my $syncidx;
  2687. my $rawData;
  2688. my $clockabs;
  2689. my $mcbitnum;
  2690. my $rssi;
  2691. my @msg_parts = SIGNALduino_splitMsg($rmsg,';'); ## Split message parts by ";"
  2692. my %ret;
  2693. my $debug = AttrVal($name,"debug",0);
  2694. foreach (@msg_parts)
  2695. {
  2696. #Debug "$name: checking msg part:( $_ )" if ($debug);
  2697. if ($_ =~ m/^MS/ or $_ =~ m/^MC/ or $_ =~ m/^MU/) #### Synced Message start
  2698. {
  2699. $ret{messagetype} = $_;
  2700. }
  2701. elsif ($_ =~ m/^P\d=-?\d{2,}/ or $_ =~ m/^[SL][LH]=-?\d{2,}/) #### Extract Pattern List from array
  2702. {
  2703. $_ =~ s/^P+//;
  2704. $_ =~ s/^P\d//;
  2705. my @pattern = split(/=/,$_);
  2706. $patternList{$pattern[0]} = $pattern[1];
  2707. Debug "$name: extracted pattern @pattern \n" if ($debug);
  2708. }
  2709. elsif($_ =~ m/D=\d+/ or $_ =~ m/^D=[A-F0-9]+/) #### Message from array
  2710. {
  2711. $_ =~ s/D=//;
  2712. $rawData = $_ ;
  2713. Debug "$name: extracted data $rawData\n" if ($debug);
  2714. $ret{rawData} = $rawData;
  2715. }
  2716. elsif($_ =~ m/^SP=\d{1}/) #### Sync Pulse Index
  2717. {
  2718. (undef, $syncidx) = split(/=/,$_);
  2719. Debug "$name: extracted syncidx $syncidx\n" if ($debug);
  2720. #return undef if (!defined($patternList{$syncidx}));
  2721. $ret{syncidx} = $syncidx;
  2722. }
  2723. elsif($_ =~ m/^CP=\d{1}/) #### Clock Pulse Index
  2724. {
  2725. (undef, $clockidx) = split(/=/,$_);
  2726. Debug "$name: extracted clockidx $clockidx\n" if ($debug);;
  2727. #return undef if (!defined($patternList{$clockidx}));
  2728. $ret{clockidx} = $clockidx;
  2729. }
  2730. elsif($_ =~ m/^L=\d/) #### MC bit length
  2731. {
  2732. (undef, $mcbitnum) = split(/=/,$_);
  2733. Debug "$name: extracted number of $mcbitnum bits\n" if ($debug);;
  2734. $ret{mcbitnum} = $mcbitnum;
  2735. }
  2736. elsif($_ =~ m/^C=\d+/) #### Message from array
  2737. {
  2738. $_ =~ s/C=//;
  2739. $clockabs = $_ ;
  2740. Debug "$name: extracted absolute clock $clockabs \n" if ($debug);
  2741. $ret{clockabs} = $clockabs;
  2742. }
  2743. elsif($_ =~ m/^R=\d+/) ### RSSI ###
  2744. {
  2745. $_ =~ s/R=//;
  2746. $rssi = $_ ;
  2747. Debug "$name: extracted RSSI $rssi \n" if ($debug);
  2748. $ret{rssi} = $rssi;
  2749. } else {
  2750. Debug "$name: unknown Message part $_" if ($debug);;
  2751. }
  2752. #print "$_\n";
  2753. }
  2754. $ret{pattern} = {%patternList};
  2755. return %ret;
  2756. }
  2757. # Function which dispatches a message if needed.
  2758. sub SIGNALduno_Dispatch($$$$$)
  2759. {
  2760. my ($hash, $rmsg, $dmsg, $rssi, $id) = @_;
  2761. my $name = $hash->{NAME};
  2762. if (!defined($dmsg))
  2763. {
  2764. Log3 $name, 5, "$name Dispatch: dmsg is undef. Skipping dispatch call";
  2765. return;
  2766. }
  2767. #Log3 $name, 5, "$name: Dispatch DMSG: $dmsg";
  2768. my $DMSGgleich = 1;
  2769. if ($dmsg eq $hash->{LASTDMSG}) {
  2770. Log3 $name, SDUINO_DISPATCH_VERBOSE, "$name Dispatch: $dmsg, test gleich";
  2771. } else {
  2772. if (defined($hash->{DoubleMsgIDs}{$id})) {
  2773. $DMSGgleich = 0;
  2774. Log3 $name, SDUINO_DISPATCH_VERBOSE, "$name Dispatch: $dmsg, test ungleich";
  2775. }
  2776. else {
  2777. Log3 $name, SDUINO_DISPATCH_VERBOSE, "$name Dispatch: $dmsg, test ungleich: disabled";
  2778. }
  2779. $hash->{LASTDMSG} = $dmsg;
  2780. }
  2781. if ($DMSGgleich) {
  2782. #Dispatch if dispatchequals is provided in protocol definition or only if $dmsg is different from last $dmsg, or if 2 seconds are between transmits
  2783. if ( (SIGNALduino_getProtoProp($id,'dispatchequals',0) eq 'true') || ($hash->{DMSG} ne $dmsg) || ($hash->{TIME}+2 < time() ) ) {
  2784. $hash->{MSGCNT}++;
  2785. $hash->{TIME} = time();
  2786. $hash->{DMSG} = $dmsg;
  2787. #my $event = 0;
  2788. if (substr(ucfirst($dmsg),0,1) eq 'U') {
  2789. #$event = 1;
  2790. DoTrigger($name, "DMSG " . $dmsg);
  2791. }
  2792. #readingsSingleUpdate($hash, "state", $hash->{READINGS}{state}{VAL}, $event);
  2793. $hash->{RAWMSG} = $rmsg;
  2794. my %addvals = (DMSG => $dmsg);
  2795. if (AttrVal($name,"suppressDeviceRawmsg",0) == 0) {
  2796. $addvals{RAWMSG} = $rmsg
  2797. }
  2798. if(defined($rssi)) {
  2799. $hash->{RSSI} = $rssi;
  2800. $addvals{RSSI} = $rssi;
  2801. $rssi .= " dB,"
  2802. }
  2803. else {
  2804. $rssi = "";
  2805. }
  2806. Log3 $name, SDUINO_DISPATCH_VERBOSE, "$name Dispatch: $dmsg, $rssi dispatch";
  2807. Dispatch($hash, $dmsg, \%addvals); ## Dispatch to other Modules
  2808. } else {
  2809. Log3 $name, 4, "$name Dispatch: $dmsg, Dropped due to short time or equal msg";
  2810. }
  2811. }
  2812. }
  2813. sub
  2814. SIGNALduino_Parse_MS($$$$%)
  2815. {
  2816. my ($hash, $iohash, $name, $rmsg,%msg_parts) = @_;
  2817. my $protocolid;
  2818. my $syncidx=$msg_parts{syncidx};
  2819. my $clockidx=$msg_parts{clockidx};
  2820. my $rawRssi=$msg_parts{rssi};
  2821. my $protocol=undef;
  2822. my $rawData=$msg_parts{rawData};
  2823. my %patternList;
  2824. my $rssi;
  2825. if (defined($rawRssi)) {
  2826. $rssi = ($rawRssi>=128 ? (($rawRssi-256)/2-74) : ($rawRssi/2-74)); # todo: passt dies so? habe ich vom 00_cul.pm
  2827. }
  2828. #$patternList{$_} = $msg_parts{rawData}{$_] for keys %msg_parts{rawData};
  2829. #$patternList = \%msg_parts{pattern};
  2830. #Debug "Message splitted:";
  2831. #Debug Dumper(\@msg_parts);
  2832. my $debug = AttrVal($iohash->{NAME},"debug",0);
  2833. if (defined($clockidx) and defined($syncidx))
  2834. {
  2835. ## Make a lookup table for our pattern index ids
  2836. #Debug "List of pattern:";
  2837. my $clockabs= $msg_parts{pattern}{$msg_parts{clockidx}};
  2838. return undef if ($clockabs == 0);
  2839. $patternList{$_} = round($msg_parts{pattern}{$_}/$clockabs,1) for keys %{$msg_parts{pattern}};
  2840. #Debug Dumper(\%patternList);
  2841. #my $syncfact = $patternList{$syncidx}/$patternList{$clockidx};
  2842. #$syncfact=$patternList{$syncidx};
  2843. #Debug "SF=$syncfact";
  2844. #### Convert rawData in Message
  2845. my $signal_length = length($rawData); # Length of data array
  2846. ## Iterate over the data_array and find zero, one, float and sync bits with the signalpattern
  2847. ## Find matching protocols
  2848. my $id;
  2849. my $message_dispatched=0;
  2850. foreach $id (@{$hash->{msIdList}}) {
  2851. my $valid=1;
  2852. #$debug=1;
  2853. Debug "Testing against Protocol id $id -> $ProtocolListSIGNALduino{$id}{name}" if ($debug);
  2854. # Check Clock if is it in range
  2855. $valid=SIGNALduino_inTol($ProtocolListSIGNALduino{$id}{clockabs},$clockabs,$clockabs*0.30) if ($ProtocolListSIGNALduino{$id}{clockabs} > 0);
  2856. Debug "validclock = $valid" if ($debug);
  2857. next if (!$valid) ;
  2858. my $bit_length = ($signal_length-(scalar @{$ProtocolListSIGNALduino{$id}{sync}}))/((scalar @{$ProtocolListSIGNALduino{$id}{one}} + scalar @{$ProtocolListSIGNALduino{$id}{zero}})/2);
  2859. #Check calculated min length
  2860. $valid = $valid && $ProtocolListSIGNALduino{$id}{length_min} <= $bit_length if (exists $ProtocolListSIGNALduino{$id}{length_min});
  2861. #Check calculated max length
  2862. $valid = $valid && $ProtocolListSIGNALduino{$id}{length_max} >= $bit_length if (exists $ProtocolListSIGNALduino{$id}{length_max});
  2863. Debug "expecting $bit_length bits in signal" if ($debug);
  2864. next if (!$valid) ;
  2865. #Debug Dumper(@{$ProtocolListSIGNALduino{$id}{sync}});
  2866. Debug "Searching in patternList: ".Dumper(\%patternList) if($debug);
  2867. Debug "searching sync: @{$ProtocolListSIGNALduino{$id}{sync}}[0] @{$ProtocolListSIGNALduino{$id}{sync}}[1]" if($debug); # z.B. [1, -18]
  2868. #$valid = $valid && SIGNALduino_inTol($patternList{$clockidx}, @{$ProtocolListSIGNALduino{$id}{sync}}[0], 3); #sync in tolerance
  2869. #$valid = $valid && SIGNALduino_inTol($patternList{$syncidx}, @{$ProtocolListSIGNALduino{$id}{sync}}[1], 3); #sync in tolerance
  2870. my $pstr;
  2871. my %patternLookupHash=();
  2872. $valid = $valid && ($pstr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{sync}},\%patternList,\$rawData)) >=0;
  2873. Debug "Found matched sync with indexes: ($pstr)" if ($debug && $valid);
  2874. $patternLookupHash{$pstr}="" if ($valid); ## Append Sync to our lookuptable
  2875. my $syncstr=$pstr; # Store for later start search
  2876. Debug "sync not found " if (!$valid && $debug); # z.B. [1, -18]
  2877. next if (!$valid) ;
  2878. $valid = $valid && ($pstr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{one}},\%patternList,\$rawData)) >=0;
  2879. Debug "Found matched one with indexes: ($pstr)" if ($debug && $valid);
  2880. $patternLookupHash{$pstr}="1" if ($valid); ## Append Sync to our lookuptable
  2881. #Debug "added $pstr " if ($debug && $valid);
  2882. Debug "one pattern not found" if ($debug && !$valid);
  2883. $valid = $valid && ($pstr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{zero}},\%patternList,\$rawData)) >=0;
  2884. Debug "Found matched zero with indexes: ($pstr)" if ($debug && $valid);
  2885. $patternLookupHash{$pstr}="0" if ($valid); ## Append Sync to our lookuptable
  2886. Debug "zero pattern not found" if ($debug && !$valid);
  2887. #Debug "added $pstr " if ($debug && $valid);
  2888. next if (!$valid) ;
  2889. #Debug "Pattern Lookup Table".Dumper(%patternLookupHash);
  2890. ## Check somethin else
  2891. #Anything seems to be valid, we can start decoding this.
  2892. Log3 $name, 4, "$name: Matched MS Protocol id $id -> $ProtocolListSIGNALduino{$id}{name}" if ($valid);
  2893. my $signal_width= @{$ProtocolListSIGNALduino{$id}{one}};
  2894. #Debug $signal_width;
  2895. my @bit_msg; # array to store decoded signal bits
  2896. #for (my $i=index($rawData,SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{sync}}))+$signal_width;$i<length($rawData);$i+=$signal_width)
  2897. #for (my $i=scalar@{$ProtocolListSIGNALduino{$id}{sync}};$i<length($rawData);$i+=$signal_width)
  2898. my $message_start =index($rawData,$syncstr)+length($syncstr);
  2899. Log3 $name, 5, "$name: Starting demodulation at Position $message_start";
  2900. for (my $i=$message_start;$i<length($rawData);$i+=$signal_width)
  2901. {
  2902. my $sig_str= substr($rawData,$i,$signal_width);
  2903. #Log3 $name, 5, "demodulating $sig_str";
  2904. #Debug $patternLookupHash{substr($rawData,$i,$signal_width)}; ## Get $signal_width number of chars from raw data string
  2905. if (exists $patternLookupHash{$sig_str}) { ## Add the bits to our bit array
  2906. push(@bit_msg,$patternLookupHash{$sig_str})
  2907. } else {
  2908. Log3 $name, 5, "$name: Found wrong signalpattern, catched ".scalar @bit_msg." bits, aborting demodulation";
  2909. last;
  2910. }
  2911. }
  2912. Debug "$name: decoded message raw (@bit_msg), ".@bit_msg." bits\n" if ($debug);;
  2913. my ($rcode,@retvalue) = SIGNALduino_callsub('postDemodulation',$ProtocolListSIGNALduino{$id}{postDemodulation},$name,@bit_msg);
  2914. next if ($rcode < 1 );
  2915. #Log3 $name, 5, "$name: postdemodulation value @retvalue";
  2916. @bit_msg = @retvalue;
  2917. undef(@retvalue); undef($rcode);
  2918. my $padwith = defined($ProtocolListSIGNALduino{$id}{paddingbits}) ? $ProtocolListSIGNALduino{$id}{paddingbits} : 4;
  2919. my $i=0;
  2920. while (scalar @bit_msg % $padwith > 0) ## will pad up full nibbles per default or full byte if specified in protocol
  2921. {
  2922. push(@bit_msg,'0');
  2923. $i++;
  2924. }
  2925. Debug "$name padded $i bits to bit_msg array" if ($debug);
  2926. #my $logmsg = SIGNALduino_padbits(@bit_msg,$padwith);
  2927. #Check converted message against lengths
  2928. $valid = $valid && $ProtocolListSIGNALduino{$id}{length_min} <= scalar @bit_msg if (defined($ProtocolListSIGNALduino{$id}{length_min}));
  2929. $valid = $valid && $ProtocolListSIGNALduino{$id}{length_max} >= scalar @bit_msg if (defined($ProtocolListSIGNALduino{$id}{length_max}));
  2930. next if (!$valid);
  2931. #my $dmsg = sprintf "%02x", oct "0b" . join "", @bit_msg; ## Array -> String -> bin -> hex
  2932. my $dmsg = SIGNALduino_b2h(join "", @bit_msg);
  2933. my $postamble = $ProtocolListSIGNALduino{$id}{postamble};
  2934. #if (defined($rawRssi)) {
  2935. #if (defined($ProtocolListSIGNALduino{$id}{preamble}) && $ProtocolListSIGNALduino{$id}{preamble} eq "s") {
  2936. # $postamble = sprintf("%02X", $rawRssi);
  2937. #} elsif ($id eq "7") {
  2938. # $postamble = "#R" . sprintf("%02X", $rawRssi);
  2939. #}
  2940. #}
  2941. $dmsg = "$dmsg".$postamble if (defined($postamble));
  2942. $dmsg = "$ProtocolListSIGNALduino{$id}{preamble}"."$dmsg" if (defined($ProtocolListSIGNALduino{$id}{preamble}));
  2943. if (defined($rssi)) {
  2944. Log3 $name, 4, "$name: Decoded MS Protocol id $id dmsg $dmsg length " . scalar @bit_msg . " RSSI = $rssi";
  2945. } else {
  2946. Log3 $name, 4, "$name: Decoded MS Protocol id $id dmsg $dmsg length " . scalar @bit_msg;
  2947. }
  2948. #my ($rcode,@retvalue) = SIGNALduino_callsub('preDispatchfunc',$ProtocolListSIGNALduino{$id}{preDispatchfunc},$name,$dmsg);
  2949. #next if (!$rcode);
  2950. #$dmsg = @retvalue;
  2951. #undef(@retvalue); undef($rcode);
  2952. my $modulematch = undef;
  2953. if (defined($ProtocolListSIGNALduino{$id}{modulematch})) {
  2954. $modulematch = $ProtocolListSIGNALduino{$id}{modulematch};
  2955. }
  2956. if (!defined($modulematch) || $dmsg =~ m/$modulematch/) {
  2957. Debug "$name: dispatching now msg: $dmsg" if ($debug);
  2958. if (defined($ProtocolListSIGNALduino{$id}{developId}) && substr($ProtocolListSIGNALduino{$id}{developId},0,1) eq "m") {
  2959. my $devid = "m$id";
  2960. my $develop = lc(AttrVal($name,"development",""));
  2961. if ($develop !~ m/$devid/) { # kein dispatch wenn die Id nicht im Attribut development steht
  2962. Log3 $name, 3, "$name: ID=$devid skiped dispatch (developId=m). To use, please add m$id to the attr development";
  2963. next;
  2964. }
  2965. }
  2966. SIGNALduno_Dispatch($hash,$rmsg,$dmsg,$rssi,$id);
  2967. $message_dispatched=1;
  2968. }
  2969. }
  2970. return 0 if (!$message_dispatched);
  2971. return 1;
  2972. }
  2973. }
  2974. ## //Todo: check list as reference
  2975. sub SIGNALduino_padbits(\@$)
  2976. {
  2977. my $i=@{$_[0]} % $_[1];
  2978. while (@{$_[0]} % $_[1] > 0) ## will pad up full nibbles per default or full byte if specified in protocol
  2979. {
  2980. push(@{$_[0]},'0');
  2981. }
  2982. return " padded $i bits to bit_msg array";
  2983. }
  2984. # - - - - - - - - - - - -
  2985. #=item SIGNALduino_getProtoProp()
  2986. #This functons, will return a value from the Protocolist and check if it is defined optional you can specify a optional default value that will be reurned
  2987. #
  2988. # returns "" if the var is not defined
  2989. # =cut
  2990. # $id, $propertyname,
  2991. sub SIGNALduino_getProtoProp
  2992. {
  2993. my ($id,$propNameLst,$default) = @_;
  2994. #my $id = shift;
  2995. #my $propNameLst = shift;
  2996. return $ProtocolListSIGNALduino{$id}{$propNameLst} if defined($ProtocolListSIGNALduino{$id}{$propNameLst});
  2997. return $default; # Will return undef if $default is not provided
  2998. #return undef;
  2999. }
  3000. sub SIGNALduino_Parse_MU($$$$@)
  3001. {
  3002. my ($hash, $iohash, $name, $rmsg,%msg_parts) = @_;
  3003. my $protocolid;
  3004. my $clockidx=$msg_parts{clockidx};
  3005. my $rssi=$msg_parts{rssi};
  3006. my $protocol=undef;
  3007. my $rawData;
  3008. my %patternListRaw;
  3009. my $message_dispatched=0;
  3010. my $debug = AttrVal($iohash->{NAME},"debug",0);
  3011. if (defined($rssi)) {
  3012. $rssi = ($rssi>=128 ? (($rssi-256)/2-74) : ($rssi/2-74)); # todo: passt dies so? habe ich vom 00_cul.pm
  3013. }
  3014. Debug "$name: processing unsynced message\n" if ($debug);
  3015. my $clockabs = 1; #Clock will be fetched from Protocol if possible
  3016. #$patternListRaw{$_} = floor($msg_parts{pattern}{$_}/$clockabs) for keys $msg_parts{pattern};
  3017. $patternListRaw{$_} = $msg_parts{pattern}{$_} for keys %{$msg_parts{pattern}};
  3018. if (defined($clockidx))
  3019. {
  3020. ## Make a lookup table for our pattern index ids
  3021. #Debug "List of pattern:"; #Debug Dumper(\%patternList);
  3022. ## Find matching protocols
  3023. my $id;
  3024. foreach $id (@{$hash->{muIdList}}) {
  3025. my $valid=1;
  3026. $clockabs= $ProtocolListSIGNALduino{$id}{clockabs};
  3027. my %patternList;
  3028. $rawData=$msg_parts{rawData};
  3029. if (exists($ProtocolListSIGNALduino{$id}{filterfunc}))
  3030. {
  3031. my $method = $ProtocolListSIGNALduino{$id}{filterfunc};
  3032. if (!exists &$method)
  3033. {
  3034. Log3 $name, 5, "$name: Error: Unknown filtermethod=$method. Please define it in file $0";
  3035. next;
  3036. } else {
  3037. Log3 $name, 5, "$name: applying filterfunc $method";
  3038. no strict "refs";
  3039. (my $count_changes,$rawData,my %patternListRaw_tmp) = $method->($name,$id,$rawData,%patternListRaw);
  3040. use strict "refs";
  3041. %patternList = map { $_ => round($patternListRaw_tmp{$_}/$clockabs,1) } keys %patternListRaw_tmp;
  3042. }
  3043. } else {
  3044. %patternList = map { $_ => round($patternListRaw{$_}/$clockabs,1) } keys %patternListRaw;
  3045. }
  3046. my $signal_length = length($rawData); # Length of data array
  3047. my @keys = sort { $patternList{$a} <=> $patternList{$b} } keys %patternList;
  3048. #Debug Dumper(\%patternList);
  3049. #Debug Dumper(@keys);
  3050. #$debug=1;
  3051. Debug "Testing against Protocol id $id -> $ProtocolListSIGNALduino{$id}{name}" if ($debug);
  3052. # $valid=SIGNALduino_inTol($ProtocolListSIGNALduino{$id}{clockabs},$clockabs,$clockabs*0.30) if ($ProtocolListSIGNALduino{$id}{clockabs} > 0);
  3053. next if (!$valid) ;
  3054. my $bit_length = ($signal_length/((scalar @{$ProtocolListSIGNALduino{$id}{one}} + scalar @{$ProtocolListSIGNALduino{$id}{zero}})/2));
  3055. Debug "Expect $bit_length bits in message" if ($valid && $debug);
  3056. #Check calculated min length
  3057. #$valid = $valid && $ProtocolListSIGNALduino{$id}{length_min} <= $bit_length if (exists $ProtocolListSIGNALduino{$id}{length_min});
  3058. #Check calculated max length
  3059. #$valid = $valid && $ProtocolListSIGNALduino{$id}{length_max} >= $bit_length if (exists $ProtocolListSIGNALduino{$id}{length_max});
  3060. #next if (!$valid) ;
  3061. #Debug "expecting $bit_length bits in signal" if ($debug && $valid);
  3062. Debug "Searching in patternList: ".Dumper(\%patternList) if($debug);
  3063. next if (!$valid) ;
  3064. my %patternLookupHash=();
  3065. #Debug "phash:".Dumper(%patternLookupHash);
  3066. my $pstr="";
  3067. $valid = $valid && ($pstr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{one}},\%patternList,\$rawData)) >=0;
  3068. Debug "Found matched one" if ($debug && $valid);
  3069. my $oneStr=$pstr if ($valid);
  3070. $patternLookupHash{$pstr}="1" if ($valid); ## Append one to our lookuptable
  3071. Debug "added $pstr " if ($debug && $valid);
  3072. my $zeroStr ="";
  3073. if (scalar @{$ProtocolListSIGNALduino{$id}{zero}} >0) {
  3074. $valid = $valid && ($pstr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{zero}},\%patternList,\$rawData)) >=0;
  3075. Debug "Found matched zero" if ($debug && $valid);
  3076. $zeroStr=$pstr if ($valid);
  3077. $patternLookupHash{$pstr}="0" if ($valid); ## Append zero to our lookuptable
  3078. Debug "added $pstr " if ($debug && $valid);
  3079. }
  3080. if (defined($ProtocolListSIGNALduino{$id}{float}))
  3081. {
  3082. $valid = $valid && ($pstr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{float}},\%patternList,\$rawData)) >=0;
  3083. Debug "Found matched float" if ($debug && $valid);
  3084. $patternLookupHash{$pstr}="F" if ($valid); ## Append float to our lookuptable
  3085. Debug "added $pstr " if ($debug && $valid);
  3086. }
  3087. next if (!$valid) ;
  3088. #Debug "Pattern Lookup Table".Dumper(%patternLookupHash);
  3089. ## Check somethin else
  3090. #Anything seems to be valid, we can start decoding this.
  3091. Log3 $name, 4, "$name: Fingerprint for MU Protocol id $id -> $ProtocolListSIGNALduino{$id}{name} matches, trying to demodulate" if ($valid);
  3092. my $signal_width= @{$ProtocolListSIGNALduino{$id}{one}};
  3093. #Debug $signal_width;
  3094. my @bit_msg=(); # array to store decoded signal bits
  3095. my $message_start=0 ;
  3096. my @msgStartLst;
  3097. my $startStr="";
  3098. my $start_regex;
  3099. #my $oneStr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{one}},\%patternList,\$rawData);
  3100. #my $zeroStr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{zero}},\%patternList,\$rawData);
  3101. if (@msgStartLst = SIGNALduino_getProtoProp($id,"start"))
  3102. {
  3103. Debug "msgStartLst: ".Dumper(@msgStartLst) if ($debug);
  3104. if ( ($startStr=SIGNALduino_PatternExists($hash,@msgStartLst,\%patternList,\$rawData)) eq -1)
  3105. {
  3106. Log3 $name, 5, "$name: start pattern for MU Protocol id $id -> $ProtocolListSIGNALduino{$id}{name} mismatches, aborting" ;
  3107. $valid=0;
  3108. next;
  3109. };
  3110. }
  3111. if (length ($zeroStr) > 0 ){ $start_regex = "$startStr\($oneStr\|$zeroStr\)";}
  3112. else {$start_regex = $startStr.$oneStr; }
  3113. Debug "Regex is: $start_regex" if ($debug);
  3114. $rawData =~ /$start_regex/;
  3115. if (defined($-[0] && $-[0] > 0)) {
  3116. $message_start=$-[0]+ length($startStr);
  3117. } else {
  3118. undef($message_start);
  3119. }
  3120. undef @msgStartLst;
  3121. #for (my $i=index($rawData,SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{sync}}))+$signal_width;$i<length($rawData);$i+=$signal_width)
  3122. Debug "Message starts at $message_start - length of data is ".length($rawData) if ($debug);
  3123. next if (!defined($message_start));
  3124. Log3 $name, 5, "$name: Starting demodulation at Position $message_start";
  3125. #my $onepos= index($rawData,SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{one}},\%patternList));
  3126. #my $zeropos=index($rawData,SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{zero}},\%patternList));
  3127. #Log3 $name, 3, "op=$onepos zp=$zeropos";
  3128. #Debug "phash:".Dumper(%patternLookupHash);
  3129. my $padwith = defined($ProtocolListSIGNALduino{$id}{paddingbits}) ? $ProtocolListSIGNALduino{$id}{paddingbits} : 4;
  3130. for (my $i=$message_start;$i<=length($rawData)-$signal_width;$i+=$signal_width)
  3131. {
  3132. my $sig_str= substr($rawData,$i,$signal_width);
  3133. Debug "$name: i=$i search=$sig_str" if ($debug);
  3134. $valid=1; # Set valid to 1 for every loop
  3135. #Debug $patternLookupHash{substr($rawData,$i,$signal_width)}; ## Get $signal_width number of chars from raw data string
  3136. if (exists $patternLookupHash{$sig_str})
  3137. {
  3138. my $bit = $patternLookupHash{$sig_str};
  3139. push(@bit_msg,$bit) if (looks_like_number($bit)) ; ## Add the bits to our bit array
  3140. }
  3141. if (!exists $patternLookupHash{$sig_str} || $i+$signal_width>length($rawData)-$signal_width) ## Dispatch if last signal or unknown data
  3142. {
  3143. Debug "$name: demodulated message raw (@bit_msg), ".@bit_msg." bits\n" if ($debug);
  3144. #Check converted message against lengths
  3145. $valid = $valid && $ProtocolListSIGNALduino{$id}{length_max} >= scalar @bit_msg if (defined($ProtocolListSIGNALduino{$id}{length_max}));
  3146. $valid = $valid && $ProtocolListSIGNALduino{$id}{length_min} <= scalar @bit_msg if (defined($ProtocolListSIGNALduino{$id}{length_min}));
  3147. #next if (!$valid); ## Last chance to try next protocol if there is somethin invalid
  3148. if ($valid) {
  3149. my ($rcode,@retvalue) = SIGNALduino_callsub('postDemodulation',$ProtocolListSIGNALduino{$id}{postDemodulation},$name,@bit_msg);
  3150. next if ($rcode < 1 );
  3151. #Log3 $name, 5, "$name: postdemodulation value @retvalue";
  3152. @bit_msg = @retvalue;
  3153. undef(@retvalue); undef($rcode);
  3154. while (scalar @bit_msg % $padwith > 0) ## will pad up full nibbles per default or full byte if specified in protocol
  3155. {
  3156. push(@bit_msg,'0');
  3157. Debug "$name: padding 0 bit to bit_msg array" if ($debug);
  3158. }
  3159. Log3 $name, 5, "$name: dispatching bits: @bit_msg";
  3160. my $dmsg = SIGNALduino_b2h(join "", @bit_msg);
  3161. $dmsg =~ s/^0+// if (defined($ProtocolListSIGNALduino{$id}{remove_zero}));
  3162. $dmsg = "$dmsg"."$ProtocolListSIGNALduino{$id}{postamble}" if (defined($ProtocolListSIGNALduino{$id}{postamble}));
  3163. $dmsg = "$ProtocolListSIGNALduino{$id}{preamble}"."$dmsg" if (defined($ProtocolListSIGNALduino{$id}{preamble}));
  3164. if (defined($rssi)) {
  3165. Log3 $name, 4, "$name: decoded matched MU Protocol id $id dmsg $dmsg length " . scalar @bit_msg . " RSSI = $rssi";
  3166. } else {
  3167. Log3 $name, 4, "$name: decoded matched MU Protocol id $id dmsg $dmsg length " . scalar @bit_msg;
  3168. }
  3169. my $modulematch;
  3170. if (defined($ProtocolListSIGNALduino{$id}{modulematch})) {
  3171. $modulematch = $ProtocolListSIGNALduino{$id}{modulematch};
  3172. }
  3173. if (!defined($modulematch) || $dmsg =~ m/$modulematch/) {
  3174. Debug "$name: dispatching now msg: $dmsg" if ($debug);
  3175. if (defined($ProtocolListSIGNALduino{$id}{developId}) && substr($ProtocolListSIGNALduino{$id}{developId},0,1) eq "m") {
  3176. my $devid = "m$id";
  3177. my $develop = lc(AttrVal($name,"development",""));
  3178. if ($develop !~ m/$devid/) { # kein dispatch wenn die Id nicht im Attribut development steht
  3179. Log3 $name, 3, "$name: ID=$devid skiped dispatch (developId=m). To use, please add m$id to the attr development";
  3180. next;
  3181. }
  3182. }
  3183. SIGNALduno_Dispatch($hash,$rmsg,$dmsg,$rssi,$id);
  3184. $message_dispatched=1;
  3185. }
  3186. } else {
  3187. if ($debug)
  3188. {
  3189. my $debugstr;
  3190. $debugstr.=$ProtocolListSIGNALduino{$id}{length_min} if defined($ProtocolListSIGNALduino{$id}{length_min});
  3191. $debugstr.="/";
  3192. $debugstr.=$ProtocolListSIGNALduino{$id}{length_max} if defined($ProtocolListSIGNALduino{$id}{length_max});
  3193. Debug "$name: length ($debugstr) does not match (@bit_msg), ".@bit_msg." bits\n";
  3194. }
  3195. }
  3196. @bit_msg=(); # clear bit_msg array
  3197. #Find next position of valid signal (skip invalid pieces)
  3198. my $regex=".{$i}".$start_regex;
  3199. Debug "$name: searching new start with ($regex)\n" if ($debug);
  3200. $rawData =~ /$regex/;
  3201. if (defined($-[0]) && ($-[0] > 0)) {
  3202. #$i=$-[0]+ $i+ length($startStr);
  3203. $i=$-[0]+ $i;
  3204. $i=$i-$signal_width if ($i>0 && length($startStr) == 0); #Todo:
  3205. Debug "$name: found restart at Position $i ($regex)\n" if ($debug);
  3206. } else {
  3207. last;
  3208. }
  3209. #if ($startStr)
  3210. #{
  3211. # $i= index($rawData,$startStr,$i);
  3212. # } else {
  3213. # $i = (index($rawData,SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{one}},\%patternList),$i+$signal_width) < index($rawData,SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{zero}},\%patternList),$i+$signal_width) ? index($rawData,SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{one}},\%patternList),$i+$signal_width) : index($rawData,SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{zero}},\%patternList),$i+$signal_width));
  3214. # $i-=$signal_width if ($i<length($rawData)-$signal_width) ;
  3215. #
  3216. # }
  3217. # last if ($i <=-1);
  3218. Log3 $name, 5, "$name: restarting demodulation at Position $i+$signal_width" if ($debug);
  3219. }
  3220. }
  3221. #my $dmsg = sprintf "%02x", oct "0b" . join "", @bit_msg; ## Array -> String -> bin -> hex
  3222. }
  3223. return 0 if (!$message_dispatched);
  3224. return 1;
  3225. }
  3226. }
  3227. sub
  3228. SIGNALduino_Parse_MC($$$$@)
  3229. {
  3230. my ($hash, $iohash, $name, $rmsg,%msg_parts) = @_;
  3231. my $clock=$msg_parts{clockabs}; ## absolute clock
  3232. my $rawData=$msg_parts{rawData};
  3233. my $rssi=$msg_parts{rssi};
  3234. my $mcbitnum=$msg_parts{mcbitnum};
  3235. my $bitData;
  3236. my $dmsg;
  3237. my $message_dispatched=0;
  3238. my $debug = AttrVal($iohash->{NAME},"debug",0);
  3239. if (defined($rssi)) {
  3240. $rssi = ($rssi>=128 ? (($rssi-256)/2-74) : ($rssi/2-74)); # todo: passt dies so? habe ich vom 00_cul.pm
  3241. }
  3242. return undef if (!$clock);
  3243. #my $protocol=undef;
  3244. #my %patternListRaw = %msg_parts{patternList};
  3245. Debug "$name: processing manchester messag len:".length($rawData) if ($debug);
  3246. my $hlen = length($rawData);
  3247. my $blen;
  3248. #if (defined($mcbitnum)) {
  3249. # $blen = $mcbitnum;
  3250. #} else {
  3251. $blen = $hlen * 4;
  3252. #}
  3253. my $id;
  3254. my $rawDataInverted;
  3255. ($rawDataInverted = $rawData) =~ tr/0123456789ABCDEF/FEDCBA9876543210/; # Some Manchester Data is inverted
  3256. foreach $id (@{$hash->{mcIdList}}) {
  3257. #next if ($blen < $ProtocolListSIGNALduino{$id}{length_min} || $blen > $ProtocolListSIGNALduino{$id}{length_max});
  3258. #if ( $clock >$ProtocolListSIGNALduino{$id}{clockrange}[0] and $clock <$ProtocolListSIGNALduino{$id}{clockrange}[1]);
  3259. if ( $clock >$ProtocolListSIGNALduino{$id}{clockrange}[0] and $clock <$ProtocolListSIGNALduino{$id}{clockrange}[1] and length($rawData)*4 >= $ProtocolListSIGNALduino{$id}{length_min} )
  3260. {
  3261. Debug "clock and min length matched" if ($debug);
  3262. if (defined($rssi)) {
  3263. Log3 $name, 4, "$name: Found manchester Protocol id $id clock $clock RSSI $rssi -> $ProtocolListSIGNALduino{$id}{name}";
  3264. } else {
  3265. Log3 $name, 4, "$name: Found manchester Protocol id $id clock $clock -> $ProtocolListSIGNALduino{$id}{name}";
  3266. }
  3267. if (exists($ProtocolListSIGNALduino{$id}{polarity}) && ($ProtocolListSIGNALduino{$id}{polarity} eq 'invert') && (!defined($hash->{version}) || substr($hash->{version},0,6) ne 'V 3.2.'))
  3268. # todo && substr($hash->{version},0,6) ne 'V 3.2.') # bei version V 3.2. nicht invertieren
  3269. {
  3270. $bitData= unpack("B$blen", pack("H$hlen", $rawDataInverted));
  3271. } else {
  3272. $bitData= unpack("B$blen", pack("H$hlen", $rawData));
  3273. }
  3274. Debug "$name: extracted data $bitData (bin)\n" if ($debug); ## Convert Message from hex to bits
  3275. Log3 $name, 5, "$name: extracted data $bitData (bin)";
  3276. my $method = $ProtocolListSIGNALduino{$id}{method};
  3277. if (!exists &$method)
  3278. {
  3279. Log3 $name, 5, "$name: Error: Unknown function=$method. Please define it in file $0";
  3280. } else {
  3281. my ($rcode,$res) = $method->($name,$bitData,$id,$mcbitnum);
  3282. if ($rcode != -1) {
  3283. $dmsg = $res;
  3284. $dmsg=$ProtocolListSIGNALduino{$id}{preamble}.$dmsg if (defined($ProtocolListSIGNALduino{$id}{preamble}));
  3285. my $modulematch;
  3286. if (defined($ProtocolListSIGNALduino{$id}{modulematch})) {
  3287. $modulematch = $ProtocolListSIGNALduino{$id}{modulematch};
  3288. }
  3289. if (!defined($modulematch) || $dmsg =~ m/$modulematch/) {
  3290. if (defined($ProtocolListSIGNALduino{$id}{developId}) && substr($ProtocolListSIGNALduino{$id}{developId},0,1) eq "m") {
  3291. my $devid = "m$id";
  3292. my $develop = lc(AttrVal($name,"development",""));
  3293. if ($develop !~ m/$devid/) { # kein dispatch wenn die Id nicht im Attribut development steht
  3294. Log3 $name, 3, "$name: ID=$devid skiped dispatch (developId=m). To use, please add m$id to the attr development";
  3295. next;
  3296. }
  3297. }
  3298. SIGNALduno_Dispatch($hash,$rmsg,$dmsg,$rssi,$id);
  3299. $message_dispatched=1;
  3300. }
  3301. } else {
  3302. $res="undef" if (!defined($res));
  3303. Log3 $name, 5, "$name: protocol does not match return from method: ($res)" ;
  3304. }
  3305. }
  3306. }
  3307. }
  3308. return 0 if (!$message_dispatched);
  3309. return 1;
  3310. }
  3311. sub
  3312. SIGNALduino_Parse($$$$@)
  3313. {
  3314. my ($hash, $iohash, $name, $rmsg, $initstr) = @_;
  3315. #print Dumper(\%ProtocolListSIGNALduino);
  3316. if (!($rmsg=~ s/^\002(M.;.*;)\003/$1/)) # Check if a Data Message arrived and if it's complete (start & end control char are received)
  3317. { # cut off start end end character from message for further processing they are not needed
  3318. Log3 $name, AttrVal($name,"noMsgVerbose",5), "$name/noMsg Parse: $rmsg";
  3319. return undef;
  3320. }
  3321. if (defined($hash->{keepalive})) {
  3322. $hash->{keepalive}{ok} = 1;
  3323. $hash->{keepalive}{retry} = 0;
  3324. }
  3325. my $debug = AttrVal($iohash->{NAME},"debug",0);
  3326. Debug "$name: incomming message: ($rmsg)\n" if ($debug);
  3327. if (AttrVal($name, "rawmsgEvent", 0)) {
  3328. DoTrigger($name, "RAWMSG " . $rmsg);
  3329. }
  3330. my %signal_parts=SIGNALduino_Split_Message($rmsg,$name); ## Split message and save anything in an hash %signal_parts
  3331. #Debug "raw data ". $signal_parts{rawData};
  3332. my $dispatched;
  3333. # Message Synced type -> M#
  3334. if (@{$hash->{msIdList}} && $rmsg=~ m/^MS;(P\d=-?\d+;){3,8}D=\d+;CP=\d;SP=\d;/)
  3335. {
  3336. $dispatched= SIGNALduino_Parse_MS($hash, $iohash, $name, $rmsg,%signal_parts);
  3337. }
  3338. # Message unsynced type -> MU
  3339. elsif (@{$hash->{muIdList}} && $rmsg=~ m/^MU;(P\d=-?\d+;){3,8}D=\d+;CP=\d;/)
  3340. {
  3341. $dispatched= SIGNALduino_Parse_MU($hash, $iohash, $name, $rmsg,%signal_parts);
  3342. }
  3343. # Manchester encoded Data -> MC
  3344. elsif (@{$hash->{mcIdList}} && $rmsg=~ m/^MC;.*;/)
  3345. {
  3346. $dispatched= SIGNALduino_Parse_MC($hash, $iohash, $name, $rmsg,%signal_parts);
  3347. }
  3348. else {
  3349. Debug "$name: unknown Messageformat, aborting\n" if ($debug);
  3350. return undef;
  3351. }
  3352. if ( AttrVal($hash->{NAME},"verbose","0") > 4 && !$dispatched)
  3353. {
  3354. my $notdisplist;
  3355. my @lines;
  3356. if (defined($hash->{unknownmessages}))
  3357. {
  3358. $notdisplist=$hash->{unknownmessages};
  3359. @lines = split ('#', $notdisplist); # or whatever
  3360. }
  3361. push(@lines,FmtDateTime(time())."-".$rmsg);
  3362. shift(@lines)if (scalar @lines >25);
  3363. $notdisplist = join('#',@lines);
  3364. $hash->{unknownmessages}=$notdisplist;
  3365. return undef;
  3366. #Todo compare Sync/Clock fact and length of D= if equal, then it's the same protocol!
  3367. }
  3368. }
  3369. #####################################
  3370. sub
  3371. SIGNALduino_Ready($)
  3372. {
  3373. my ($hash) = @_;
  3374. if ($hash->{STATE} eq 'disconnected') {
  3375. $hash->{DevState} = 'disconnected';
  3376. return DevIo_OpenDev($hash, 1, "SIGNALduino_DoInit", 'SIGNALduino_Connect')
  3377. }
  3378. # This is relevant for windows/USB only
  3379. my $po = $hash->{USBDev};
  3380. my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags);
  3381. if($po) {
  3382. ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags) = $po->status;
  3383. }
  3384. return ($InBytes && $InBytes>0);
  3385. }
  3386. sub
  3387. SIGNALduino_WriteInit($)
  3388. {
  3389. my ($hash) = @_;
  3390. # todo: ist dies so ausreichend, damit die Aenderungen uebernommen werden?
  3391. SIGNALduino_AddSendQueue($hash,"WS36"); # SIDLE, Exit RX / TX, turn off frequency synthesizer
  3392. SIGNALduino_AddSendQueue($hash,"WS34"); # SRX, Enable RX. Perform calibration first if coming from IDLE and MCSM0.FS_AUTOCAL=1.
  3393. }
  3394. ########################
  3395. sub
  3396. SIGNALduino_SimpleWrite(@)
  3397. {
  3398. my ($hash, $msg, $nonl) = @_;
  3399. return if(!$hash);
  3400. if($hash->{TYPE} eq "SIGNALduino_RFR") {
  3401. # Prefix $msg with RRBBU and return the corresponding SIGNALduino hash.
  3402. ($hash, $msg) = SIGNALduino_RFR_AddPrefix($hash, $msg);
  3403. }
  3404. my $name = $hash->{NAME};
  3405. Log3 $name, 5, "$name SW: $msg";
  3406. $msg .= "\n" unless($nonl);
  3407. $hash->{USBDev}->write($msg) if($hash->{USBDev});
  3408. syswrite($hash->{TCPDev}, $msg) if($hash->{TCPDev});
  3409. syswrite($hash->{DIODev}, $msg) if($hash->{DIODev});
  3410. # Some linux installations are broken with 0.001, T01 returns no answer
  3411. select(undef, undef, undef, 0.01);
  3412. }
  3413. sub
  3414. SIGNALduino_Attr(@)
  3415. {
  3416. my ($cmd,$name,$aName,$aVal) = @_;
  3417. my $hash = $defs{$name};
  3418. my $debug = AttrVal($name,"debug",0);
  3419. $aVal= "" if (!defined($aVal));
  3420. Log3 $name, 4, "$name: Calling Getting Attr sub with args: $cmd $aName = $aVal";
  3421. if( $aName eq "Clients" ) { ## Change clientList
  3422. $hash->{Clients} = $aVal;
  3423. $hash->{Clients} = $clientsSIGNALduino if( !$hash->{Clients}) ; ## Set defaults
  3424. return "Setting defaults";
  3425. } elsif( $aName eq "MatchList" ) { ## Change matchList
  3426. my $match_list;
  3427. if( $cmd eq "set" ) {
  3428. $match_list = eval $aVal;
  3429. if( $@ ) {
  3430. Log3 $name, 2, $name .": $aVal: ". $@;
  3431. }
  3432. }
  3433. if( ref($match_list) eq 'HASH' ) {
  3434. $hash->{MatchList} = $match_list;
  3435. } else {
  3436. $hash->{MatchList} = \%matchListSIGNALduino; ## Set defaults
  3437. Log3 $name, 2, $name .": $aVal: not a HASH using defaults" if( $aVal );
  3438. }
  3439. }
  3440. elsif ($aName eq "verbose")
  3441. {
  3442. Log3 $name, 3, "$name: setting Verbose to: " . $aVal;
  3443. $hash->{unknownmessages}="" if $aVal <4;
  3444. }
  3445. elsif ($aName eq "debug")
  3446. {
  3447. $debug = $aVal;
  3448. Log3 $name, 3, "$name: setting debug to: " . $debug;
  3449. }
  3450. elsif ($aName eq "whitelist_IDs")
  3451. {
  3452. Log3 $name, 3, "$name Attr: whitelist_IDs";
  3453. if ($init_done) { # beim fhem Start wird das SIGNALduino_IdList nicht aufgerufen, da es beim define aufgerufen wird
  3454. SIGNALduino_IdList("x:$name",$aVal);
  3455. }
  3456. }
  3457. elsif ($aName eq "blacklist_IDs")
  3458. {
  3459. Log3 $name, 3, "$name Attr: blacklist_IDs";
  3460. if ($init_done) { # beim fhem Start wird das SIGNALduino_IdList nicht aufgerufen, da es beim define aufgerufen wird
  3461. SIGNALduino_IdList("x:$name",undef,$aVal);
  3462. }
  3463. }
  3464. elsif ($aName eq "development")
  3465. {
  3466. Log3 $name, 3, "$name Attr: development";
  3467. if ($init_done) { # beim fhem Start wird das SIGNALduino_IdList nicht aufgerufen, da es beim define aufgerufen wird
  3468. SIGNALduino_IdList("x:$name",undef,undef,$aVal);
  3469. }
  3470. }
  3471. elsif ($aName eq "doubleMsgCheck_IDs")
  3472. {
  3473. if (defined($aVal)) {
  3474. if (length($aVal)>0) {
  3475. if (substr($aVal,0 ,1) eq '#') {
  3476. Log3 $name, 3, "$name Attr: doubleMsgCheck_IDs disabled: $aVal";
  3477. delete $hash->{DoubleMsgIDs};
  3478. }
  3479. else {
  3480. Log3 $name, 3, "$name Attr: doubleMsgCheck_IDs enabled: $aVal";
  3481. my %DoubleMsgiD = map { $_ => 1 } split(",", $aVal);
  3482. $hash->{DoubleMsgIDs} = \%DoubleMsgiD;
  3483. #print Dumper $hash->{DoubleMsgIDs};
  3484. }
  3485. }
  3486. else {
  3487. Log3 $name, 3, "$name delete Attr: doubleMsgCheck_IDs";
  3488. delete $hash->{DoubleMsgIDs};
  3489. }
  3490. }
  3491. }
  3492. elsif ($aName eq "cc1101_frequency")
  3493. {
  3494. if ($aVal eq "" || $aVal < 800) {
  3495. Log3 $name, 3, "$name: delete cc1101_frequeny";
  3496. delete ($hash->{cc1101_frequency}) if (defined($hash->{cc1101_frequency}));
  3497. } else {
  3498. Log3 $name, 3, "$name: setting cc1101_frequency to 868";
  3499. $hash->{cc1101_frequency} = 868;
  3500. }
  3501. }
  3502. return undef;
  3503. }
  3504. sub SIGNALduino_IdList($@)
  3505. {
  3506. my ($param, $aVal, $blacklist, $develop) = @_;
  3507. my (undef,$name) = split(':', $param);
  3508. my $hash = $defs{$name};
  3509. my @msIdList = ();
  3510. my @muIdList = ();
  3511. my @mcIdList = ();
  3512. if (!defined($aVal)) {
  3513. $aVal = AttrVal($name,"whitelist_IDs","");
  3514. }
  3515. Log3 $name, 3, "$name sduinoIdList: whitelistIds=$aVal";
  3516. if (!defined($blacklist)) {
  3517. $blacklist = AttrVal($name,"blacklist_IDs","");
  3518. }
  3519. Log3 $name, 3, "$name sduinoIdList: blacklistIds=$blacklist";
  3520. if (!defined($develop)) {
  3521. $develop = AttrVal($name,"development","");
  3522. }
  3523. $develop = lc($develop);
  3524. Log3 $name, 3, "$name sduinoIdList: development=$develop";
  3525. my %WhitelistIDs;
  3526. my %BlacklistIDs;
  3527. my $wflag = 0; # whitelist flag, 0=disabled
  3528. my $bflag = 0; # blacklist flag, 0=disabled
  3529. if (defined($aVal) && length($aVal)>0)
  3530. {
  3531. if (substr($aVal,0 ,1) eq '#') {
  3532. Log3 $name, 3, "$name Attr whitelist disabled: $aVal";
  3533. }
  3534. else {
  3535. %WhitelistIDs = map { $_ => 1 } split(",", $aVal);
  3536. #my $w = join ', ' => map "$_" => keys %WhitelistIDs;
  3537. #Log3 $name, 3, "Attr whitelist $w";
  3538. $wflag = 1;
  3539. }
  3540. }
  3541. if ($wflag == 0) { # whitelist disabled
  3542. if (defined($blacklist) && length($blacklist)>0) {
  3543. %BlacklistIDs = map { $_ => 1 } split(",", $blacklist);
  3544. my $w = join ', ' => map "$_" => keys %BlacklistIDs;
  3545. Log3 $name, 3, "$name Attr blacklist $w";
  3546. $bflag = 1;
  3547. }
  3548. }
  3549. my $id;
  3550. foreach $id (keys %ProtocolListSIGNALduino)
  3551. {
  3552. next if ($id eq 'id');
  3553. if ($wflag == 1 && !defined($WhitelistIDs{$id}))
  3554. {
  3555. #Log3 $name, 3, "skip ID $id";
  3556. next;
  3557. }
  3558. if ($bflag == 1 && defined($BlacklistIDs{$id}))
  3559. {
  3560. Log3 $name, 3, "$name skip Blacklist ID $id";
  3561. next;
  3562. }
  3563. if (defined($ProtocolListSIGNALduino{$id}{developId}) && substr($ProtocolListSIGNALduino{$id}{developId},0,1) eq "p") {
  3564. my $devid = "p$id";
  3565. if ($develop !~ m/$devid/) { # skip wenn die Id nicht im Attribut development steht
  3566. Log3 $name, 3, "$name: ID=$devid skiped (developId=p)";
  3567. next;
  3568. }
  3569. }
  3570. if (defined($ProtocolListSIGNALduino{$id}{developId}) && substr($ProtocolListSIGNALduino{$id}{developId},0,1) eq "y") {
  3571. if ($develop !~ m/y/) { # skip wenn y nicht im Attribut development steht
  3572. Log3 $name, 3, "$name: ID=$id skiped (developId=y)";
  3573. next;
  3574. }
  3575. }
  3576. if (exists ($ProtocolListSIGNALduino{$id}{format}) && $ProtocolListSIGNALduino{$id}{format} eq "manchester")
  3577. {
  3578. push (@mcIdList, $id);
  3579. }
  3580. elsif (exists $ProtocolListSIGNALduino{$id}{sync})
  3581. {
  3582. push (@msIdList, $id);
  3583. }
  3584. elsif (exists ($ProtocolListSIGNALduino{$id}{clockabs}))
  3585. {
  3586. push (@muIdList, $id);
  3587. }
  3588. }
  3589. @msIdList = sort @msIdList;
  3590. @muIdList = sort @muIdList;
  3591. @mcIdList = sort @mcIdList;
  3592. Log3 $name, 3, "$name: IDlist MS @msIdList";
  3593. Log3 $name, 3, "$name: IDlist MU @muIdList";
  3594. Log3 $name, 3, "$name: IDlist MC @mcIdList";
  3595. $hash->{msIdList} = \@msIdList;
  3596. $hash->{muIdList} = \@muIdList;
  3597. $hash->{mcIdList} = \@mcIdList;
  3598. }
  3599. sub SIGNALduino_callsub
  3600. {
  3601. my $funcname =shift;
  3602. my $method = shift;
  3603. my $name = shift;
  3604. my @args = @_;
  3605. if ( defined $method && defined &$method )
  3606. {
  3607. #my $subname = @{[eval {&$method}, $@ =~ /.*/]};
  3608. Log3 $name, 5, "$name: applying $funcname"; # method $subname";
  3609. #Log3 $name, 5, "$name: value bevore $funcname: @args";
  3610. my ($rcode, @returnvalues) = $method->($name, @args) ;
  3611. if (@returnvalues && defined($returnvalues[0])) {
  3612. SIGNALduino_Log3 $name, 5, "$name: rcode=$rcode, modified value after $funcname: @returnvalues";
  3613. } else {
  3614. SIGNALduino_Log3 $name, 5, "$name: rcode=$rcode, after calling $funcname";
  3615. }
  3616. return ($rcode, @returnvalues);
  3617. } elsif (defined $method ) {
  3618. Log3 $name, 5, "$name: Error: Unknown method $funcname Please check definition";
  3619. return (0,undef);
  3620. }
  3621. return (1,@args);
  3622. }
  3623. # calculates the hex (in bits) and adds it at the beginning of the message
  3624. # input = @list
  3625. # output = @list
  3626. sub SIGNALduino_lengtnPrefix
  3627. {
  3628. my ($name, @bit_msg) = @_;
  3629. my $msg = join("",@bit_msg);
  3630. #$msg = unpack("B8", pack("N", length($msg))).$msg;
  3631. $msg=sprintf('%08b', length($msg)).$msg;
  3632. return (1,split("",$msg));
  3633. }
  3634. sub SIGNALduino_bit2Arctec
  3635. {
  3636. my ($name, @bit_msg) = @_;
  3637. my $msg = join("",@bit_msg);
  3638. # Convert 0 -> 01 1 -> 10 to be compatible with IT Module
  3639. $msg =~ s/0/z/g;
  3640. $msg =~ s/1/10/g;
  3641. $msg =~ s/z/01/g;
  3642. return (1,split("",$msg));
  3643. }
  3644. sub SIGNALduino_ITV1_tristateToBit($)
  3645. {
  3646. my ($msg) = @_;
  3647. # Convert 0 -> 00 1 -> 11 F => 01 to be compatible with IT Module
  3648. $msg =~ s/0/00/g;
  3649. $msg =~ s/1/11/g;
  3650. $msg =~ s/F/01/g;
  3651. $msg =~ s/D/10/g;
  3652. return (1,$msg);
  3653. }
  3654. sub SIGNALduino_HE($@) {
  3655. my ($name, @bit_msg) = @_;
  3656. my $msg = join("",@bit_msg);
  3657. #Log3 $name, 4, "$name HE: $msg";
  3658. Log3 $name, 4, "$name HE: " . substr($msg,0,11) ." ". substr($msg,11,32) ." ". substr($msg,43,4) ." ". substr($msg,47,2) ." ". substr($msg,49,2) ." ". substr($msg,51);
  3659. return (1,split("",$msg));
  3660. }
  3661. sub SIGNALduino_postDemo_Hoermann($@) {
  3662. my ($name, @bit_msg) = @_;
  3663. my $msg = join("",@bit_msg);
  3664. if (substr($msg,0,9) ne "000000001") { # check ident
  3665. Log3 $name, 4, "$name: Hoermann ERROR - Ident not 000000001";
  3666. return 0, undef;
  3667. } else {
  3668. Log3 $name, 5, "$name: Hoermann $msg";
  3669. $msg = substr($msg,9);
  3670. return (1,split("",$msg));
  3671. }
  3672. }
  3673. sub SIGNALduino_postDemo_FS20($@) {
  3674. my ($name, @bit_msg) = @_;
  3675. my $datastart = 0;
  3676. my $protolength = scalar @bit_msg;
  3677. my $sum = 0;
  3678. my $b = 0;
  3679. my $i = 0;
  3680. for ($datastart = 0; $datastart < $protolength; $datastart++) { # Start bei erstem Bit mit Wert 1 suchen
  3681. last if $bit_msg[$datastart] eq "1";
  3682. }
  3683. if ($datastart == $protolength) { # all bits are 0
  3684. Log3 $name, 3, "$name: FS20 - ERROR message all bit are zeros";
  3685. return 0, undef;
  3686. }
  3687. splice(@bit_msg, 0, $datastart + 1); # delete preamble + 1 bit
  3688. $protolength = scalar @bit_msg;
  3689. if ($protolength == 45) { ### FS20 length 45 or 54
  3690. for(my $b = 0; $b < 36; $b += 9) { # build sum over first 4 bytes
  3691. $sum += oct( "0b".(join "", @bit_msg[$b .. $b + 7]));
  3692. }
  3693. my $checksum = oct( "0b".(join "", @bit_msg[36 .. 43])); # Checksum Byte 5
  3694. if (((($sum + 6) & 0xFF) - $checksum) == 0) { ## FHT80TF Tuer-/Fensterkontakt
  3695. for(my $b = 0; $b < 45; $b += 9) { # check parity over 5 byte
  3696. my $parity = 0; # Parity even
  3697. for(my $i = $b; $i < $b + 9; $i++) { # Parity over 1 byte + 1 bit
  3698. $parity += $bit_msg[$i];
  3699. }
  3700. if ($parity % 2 != 0) {
  3701. Log3 $name, 3, "$name: FS20 ERROR - Parity not even";
  3702. return 0, undef;
  3703. }
  3704. } # parity ok
  3705. for(my $b = 44; $b > 0; $b -= 9) { # delete 5 parity bits
  3706. splice(@bit_msg, $b, 1);
  3707. }
  3708. splice(@bit_msg, 32, 8); # delete checksum
  3709. splice(@bit_msg, 24, 0, (0,0,0,0,0,0,0,0)); # insert Byte 3
  3710. Log3 $name, 4, "$name: FS20 - remote control protolength $protolength";
  3711. return (1, @bit_msg); ## FHT80TF ok
  3712. }
  3713. }
  3714. if ($protolength == 54) { ### FS20 length 45 or 54
  3715. for($b = 0; $b < 45; $b += 9) { # build sum over first 5 bytes
  3716. $sum += oct( "0b".(join "", @bit_msg[$b .. $b + 7]));
  3717. }
  3718. my $checksum = oct( "0b".(join "", @bit_msg[45 .. 52])); # Checksum Byte 6
  3719. if (((($sum + 6) & 0xFF) - $checksum) == 0) { ## FHT80 Raumthermostat
  3720. for($b = 0; $b < 55; $b += 9) { # check parity over 6 byte
  3721. my $parity = 0; # Parity even
  3722. for($i = $b; $i < $b + 9; $i++) { # Parity over 1 byte + 1 bit
  3723. $parity += $bit_msg[$i];
  3724. }
  3725. if ($parity % 2 != 0) {
  3726. Log3 $name, 3, "$name: FHT80 ERROR - Parity not even";
  3727. return 0, undef;
  3728. }
  3729. } # parity ok
  3730. for($b = 53; $b > 0; $b -= 9) { # delete 6 parity bits
  3731. splice(@bit_msg, $b, 1);
  3732. }
  3733. splice(@bit_msg, 40, 8); # delete checksum
  3734. Log3 $name, 4, "$name: FS20 - remote control protolength $protolength";
  3735. return (1, @bit_msg); ## FHT80 ok
  3736. }
  3737. }
  3738. return 0, undef;
  3739. }
  3740. sub SIGNALduino_postDemo_FHT80($@) {
  3741. my ($name, @bit_msg) = @_;
  3742. my $datastart = 0;
  3743. my $protolength = scalar @bit_msg;
  3744. my $sum = 0;
  3745. my $b = 0;
  3746. my $i = 0;
  3747. # if ($protolength < 66) { # min 6 bytes + 6 bits
  3748. # Log3 $name, 3, "$name: FHT80 - ERROR lenght of message < 66";
  3749. # return 0, undef;
  3750. # }
  3751. for ($datastart = 0; $datastart < $protolength; $datastart++) { # Start bei erstem Bit mit Wert 1 suchen
  3752. last if $bit_msg[$datastart] eq "1";
  3753. }
  3754. if ($datastart == $protolength) { # all bits are 0
  3755. Log3 $name, 3, "$name: FHT80 - ERROR message all bit are zeros";
  3756. return 0, undef;
  3757. }
  3758. splice(@bit_msg, 0, $datastart + 1); # delete preamble + 1 bit
  3759. $protolength = scalar @bit_msg;
  3760. if ($protolength == 54) { ### FHT80 fixed length
  3761. for($b = 0; $b < 45; $b += 9) { # build sum over first 5 bytes
  3762. $sum += oct( "0b".(join "", @bit_msg[$b .. $b + 7]));
  3763. }
  3764. my $checksum = oct( "0b".(join "", @bit_msg[45 .. 52])); # Checksum Byte 6
  3765. if (((($sum + 12) & 0xFF) - $checksum) == 0) { ## FHT80 Raumthermostat
  3766. for($b = 0; $b < 55; $b += 9) { # check parity over 6 byte
  3767. my $parity = 0; # Parity even
  3768. for($i = $b; $i < $b + 9; $i++) { # Parity over 1 byte + 1 bit
  3769. $parity += $bit_msg[$i];
  3770. }
  3771. if ($parity % 2 != 0) {
  3772. Log3 $name, 3, "$name: FHT80 ERROR - Parity not even";
  3773. return 0, undef;
  3774. }
  3775. } # parity ok
  3776. for($b = 53; $b > 0; $b -= 9) { # delete 6 parity bits
  3777. splice(@bit_msg, $b, 1);
  3778. }
  3779. if ($bit_msg[26] != 1) { # Bit 5 Byte 3 must 1
  3780. Log3 $name, 3, "$name: FHT80 ERROR - byte 3 bit 5 not 1";
  3781. return 0, undef;
  3782. }
  3783. splice(@bit_msg, 40, 8); # delete checksum
  3784. splice(@bit_msg, 24, 0, (0,0,0,0,0,0,0,0)); # insert Byte 3
  3785. Log3 $name, 4, "$name: FHT80 - roomthermostat protolength $protolength";
  3786. return (1, @bit_msg); ## FHT80 ok
  3787. }
  3788. }
  3789. return 0, undef;
  3790. }
  3791. sub SIGNALduino_postDemo_FHT80TF($@) {
  3792. my ($name, @bit_msg) = @_;
  3793. my $datastart = 0;
  3794. my $protolength = scalar @bit_msg;
  3795. my $sum = 0;
  3796. my $b = 0;
  3797. if ($protolength < 46) { # min 5 bytes + 6 bits
  3798. Log3 $name, 4, "$name: FHT80TF or FS20 - ERROR lenght of message < 46";
  3799. return 0, undef;
  3800. }
  3801. for ($datastart = 0; $datastart < $protolength; $datastart++) { # Start bei erstem Bit mit Wert 1 suchen
  3802. last if $bit_msg[$datastart] eq "1";
  3803. }
  3804. if ($datastart == $protolength) { # all bits are 0
  3805. Log3 $name, 3, "$name: FHTTF or FS20 - ERROR message all bit are zeros";
  3806. return 0, undef;
  3807. }
  3808. splice(@bit_msg, 0, $datastart + 1); # delete preamble + 1 bit
  3809. $protolength = scalar @bit_msg;
  3810. if ($protolength == 45) { ### FHT80TF fixed length
  3811. for(my $b = 0; $b < 36; $b += 9) { # build sum over first 4 bytes
  3812. $sum += oct( "0b".(join "", @bit_msg[$b .. $b + 7]));
  3813. }
  3814. my $checksum = oct( "0b".(join "", @bit_msg[36 .. 43])); # Checksum Byte 5
  3815. if (((($sum + 12) & 0xFF) - $checksum) == 0) { ## FHT80TF Tuer-/Fensterkontakt
  3816. for(my $b = 0; $b < 45; $b += 9) { # check parity over 5 byte
  3817. my $parity = 0; # Parity even
  3818. for(my $i = $b; $i < $b + 9; $i++) { # Parity over 1 byte + 1 bit
  3819. $parity += $bit_msg[$i];
  3820. }
  3821. if ($parity % 2 != 0) {
  3822. Log3 $name, 4, "$name: FHT80TF ERROR - Parity not even";
  3823. return 0, undef;
  3824. }
  3825. } # parity ok
  3826. for(my $b = 44; $b > 0; $b -= 9) { # delete 5 parity bits
  3827. splice(@bit_msg, $b, 1);
  3828. }
  3829. if ($bit_msg[26] != 0) { # Bit 5 Byte 3 must 0
  3830. Log3 $name, 3, "$name: FHT80 ERROR - byte 3 bit 5 not 0";
  3831. return 0, undef;
  3832. }
  3833. splice(@bit_msg, 32, 8); # delete checksum
  3834. Log3 $name, 4, "$name: FHT80TF - door/window switch protolength $protolength";
  3835. return (1, @bit_msg); ## FHT80TF ok
  3836. }
  3837. }
  3838. return 0, undef;
  3839. }
  3840. sub SIGNALduino_postDemo_WS7035($@) {
  3841. my ($name, @bit_msg) = @_;
  3842. my $msg = join("",@bit_msg);
  3843. my $parity = 0; # Parity even
  3844. Log3 $name, 4, "$name: WS7035 $msg";
  3845. if (substr($msg,0,8) ne "10100000") { # check ident
  3846. Log3 $name, 3, "$name: WS7035 ERROR - Ident not 1010 0000";
  3847. return 0, undef;
  3848. } else {
  3849. for(my $i = 15; $i < 28; $i++) { # Parity over bit 15 and 12 bit temperature
  3850. $parity += substr($msg, $i, 1);
  3851. }
  3852. if ($parity % 2 != 0) {
  3853. Log3 $name, 3, "$name: WS7035 ERROR - Parity not even";
  3854. return 0, undef;
  3855. } else {
  3856. Log3 $name, 4, "$name: WS7035 " . substr($msg,0,4) ." ". substr($msg,4,4) ." ". substr($msg,8,4) ." ". substr($msg,12,4) ." ". substr($msg,16,4) ." ". substr($msg,20,4) ." ". substr($msg,24,4) ." ". substr($msg,28,4) ." ". substr($msg,32,4) ." ". substr($msg,36,4) ." ". substr($msg,40);
  3857. substr($msg, 27, 4, ''); # delete nibble 8
  3858. return (1,split("",$msg));
  3859. }
  3860. }
  3861. }
  3862. sub SIGNALduino_postDemo_WS2000($@) {
  3863. my ($name, @bit_msg) = @_;
  3864. my $debug = AttrVal($name,"debug",0);
  3865. my @new_bit_msg = "";
  3866. my $protolength = scalar @bit_msg;
  3867. my @datalenghtws = (35,50,35,50,70,40,40,85);
  3868. my $datastart = 0;
  3869. my $datalength = 0;
  3870. my $datalength1 = 0;
  3871. my $index = 0;
  3872. my $data = 0;
  3873. my $dataindex = 0;
  3874. my $error = 0;
  3875. my $check = 0;
  3876. my $sum = 5;
  3877. my $typ = 0;
  3878. my $adr = 0;
  3879. my @sensors = (
  3880. "Thermo",
  3881. "Thermo/Hygro",
  3882. "Rain",
  3883. "Wind",
  3884. "Thermo/Hygro/Baro",
  3885. "Brightness",
  3886. "Pyrano",
  3887. "Kombi"
  3888. );
  3889. for ($datastart = 0; $datastart < $protolength; $datastart++) { # Start bei erstem Bit mit Wert 1 suchen
  3890. last if $bit_msg[$datastart] eq "1";
  3891. }
  3892. if ($datastart == $protolength) { # all bits are 0
  3893. Log3 $name, 3, "$name: WS2000 - ERROR message all bit are zeros";
  3894. return 0, undef;
  3895. }
  3896. $datalength = $protolength - $datastart;
  3897. $datalength1 = $datalength - ($datalength % 5); # modulo 5
  3898. Log3 $name, 5, "$name: WS2000 protolength: $protolength, datastart: $datastart, datalength $datalength";
  3899. $typ = oct( "0b".(join "", reverse @bit_msg[$datastart + 1.. $datastart + 4])); # Sensortyp
  3900. if ($typ > 7) {
  3901. Log3 $name, 4, "$name: WS2000 Sensortyp $typ - ERROR typ to big";
  3902. return 0, undef;
  3903. }
  3904. if ($typ == 1 && ($datalength == 45 || $datalength == 46)) {$datalength1 += 5;} # Typ 1 ohne Summe
  3905. if ($datalenghtws[$typ] != $datalength1) { # check lenght of message
  3906. Log3 $name, 4, "$name: WS2000 Sensortyp $typ - ERROR lenght of message $datalength1 ($datalenghtws[$typ])";
  3907. return 0, undef;
  3908. } elsif ($datastart > 10) { # max 10 Bit preamble
  3909. Log3 $name, 4, "$name: WS2000 ERROR preamble > 10 ($datastart)";
  3910. return 0, undef;
  3911. } else {
  3912. do {
  3913. $error += !$bit_msg[$index + $datastart]; # jedes 5. Bit muss 1 sein
  3914. $dataindex = $index + $datastart + 1;
  3915. $data = oct( "0b".(join "", reverse @bit_msg[$dataindex .. $dataindex + 3]));
  3916. if ($index == 5) {$adr = ($data & 0x07)} # Sensoradresse
  3917. if ($datalength == 45 || $datalength == 46) { # Typ 1 ohne Summe
  3918. if ($index <= $datalength - 5) {
  3919. $check = $check ^ $data; # Check - Typ XOR Adresse XOR bis XOR Check muss 0 ergeben
  3920. }
  3921. } else {
  3922. if ($index <= $datalength - 10) {
  3923. $check = $check ^ $data; # Check - Typ XOR Adresse XOR bis XOR Check muss 0 ergeben
  3924. $sum += $data;
  3925. }
  3926. }
  3927. $index += 5;
  3928. } until ($index >= $datalength -1 );
  3929. }
  3930. if ($error != 0) {
  3931. Log3 $name, 4, "$name: WS2000 Sensortyp $typ Adr $adr - ERROR examination bit";
  3932. return (0, undef);
  3933. } elsif ($check != 0) {
  3934. Log3 $name, 4, "$name: WS2000 Sensortyp $typ Adr $adr - ERROR check XOR";
  3935. return (0, undef);
  3936. } else {
  3937. if ($datalength < 45 || $datalength > 46) { # Summe prüfen, außer Typ 1 ohne Summe
  3938. $data = oct( "0b".(join "", reverse @bit_msg[$dataindex .. $dataindex + 3]));
  3939. if ($data != ($sum & 0x0F)) {
  3940. Log3 $name, 4, "$name: WS2000 Sensortyp $typ Adr $adr - ERROR sum";
  3941. return (0, undef);
  3942. }
  3943. }
  3944. Log3 $name, 4, "$name: WS2000 Sensortyp $typ Adr $adr - $sensors[$typ]";
  3945. $datastart += 1; # [x] - 14_CUL_WS
  3946. @new_bit_msg[4 .. 7] = reverse @bit_msg[$datastart .. $datastart+3]; # [2] Sensortyp
  3947. @new_bit_msg[0 .. 3] = reverse @bit_msg[$datastart+5 .. $datastart+8]; # [1] Sensoradresse
  3948. @new_bit_msg[12 .. 15] = reverse @bit_msg[$datastart+10 .. $datastart+13]; # [4] T 0.1, R LSN, Wi 0.1, B 1, Py 1
  3949. @new_bit_msg[8 .. 11] = reverse @bit_msg[$datastart+15 .. $datastart+18]; # [3] T 1, R MID, Wi 1, B 10, Py 10
  3950. if ($typ == 0 || $typ == 2) { # Thermo (AS3), Rain (S2000R, WS7000-16)
  3951. @new_bit_msg[16 .. 19] = reverse @bit_msg[$datastart+20 .. $datastart+23]; # [5] T 10, R MSN
  3952. } else {
  3953. @new_bit_msg[20 .. 23] = reverse @bit_msg[$datastart+20 .. $datastart+23]; # [6] T 10, Wi 10, B 100, Py 100
  3954. @new_bit_msg[16 .. 19] = reverse @bit_msg[$datastart+25 .. $datastart+28]; # [5] H 0.1, Wr 1, B Fak, Py Fak
  3955. if ($typ == 1 || $typ == 3 || $typ == 4 || $typ == 7) { # Thermo/Hygro, Wind, Thermo/Hygro/Baro, Kombi
  3956. @new_bit_msg[28 .. 31] = reverse @bit_msg[$datastart+30 .. $datastart+33]; # [8] H 1, Wr 10
  3957. @new_bit_msg[24 .. 27] = reverse @bit_msg[$datastart+35 .. $datastart+38]; # [7] H 10, Wr 100
  3958. if ($typ == 4) { # Thermo/Hygro/Baro (S2001I, S2001ID)
  3959. @new_bit_msg[36 .. 39] = reverse @bit_msg[$datastart+40 .. $datastart+43]; # [10] P 1
  3960. @new_bit_msg[32 .. 35] = reverse @bit_msg[$datastart+45 .. $datastart+48]; # [9] P 10
  3961. @new_bit_msg[44 .. 47] = reverse @bit_msg[$datastart+50 .. $datastart+53]; # [12] P 100
  3962. @new_bit_msg[40 .. 43] = reverse @bit_msg[$datastart+55 .. $datastart+58]; # [11] P Null
  3963. }
  3964. }
  3965. }
  3966. return (1, @new_bit_msg);
  3967. }
  3968. }
  3969. sub SIGNALduino_postDemo_WS7053($@) {
  3970. my ($name, @bit_msg) = @_;
  3971. my $msg = join("",@bit_msg);
  3972. my $new_msg ="";
  3973. my $parity = 0; # Parity even
  3974. if (length($msg) > 32) { # start not correct
  3975. $msg = substr($msg,1)
  3976. }
  3977. Log3 $name, 4, "$name: WS7053 MSG = $msg";
  3978. if (substr($msg,0,8) ne "10100000") { # check ident
  3979. Log3 $name, 3, "$name: WS7053 ERROR - Ident not 1010 0000 - " . substr($msg,0,8);
  3980. return 0, undef;
  3981. } else {
  3982. for(my $i = 15; $i < 28; $i++) { # Parity over bit 15 and 12 bit temperature
  3983. $parity += substr($msg, $i, 1);
  3984. }
  3985. if ($parity % 2 != 0) {
  3986. Log3 $name, 3, "$name: WS7053 ERROR - Parity not even";
  3987. return 0, undef;
  3988. } else {
  3989. Log3 $name, 5, "$name: WS7053 before: " . substr($msg,0,4) ." ". substr($msg,4,4) ." ". substr($msg,8,4) ." ". substr($msg,12,4) ." ". substr($msg,16,4) ." ". substr($msg,20,4) ." ". substr($msg,24,4) ." ". substr($msg,28,4);
  3990. # Format from 7053: Bit 0-7 Ident, Bit 8-15 Rolling Code/Parity, Bit 16-27 Temperature (12.3), Bit 28-31 Zero
  3991. $new_msg = substr($msg,0,28) . substr($msg,16,8) . substr($msg,28,4);
  3992. # Format for CUL_TX: Bit 0-7 Ident, Bit 8-15 Rolling Code/Parity, Bit 16-27 Temperature (12.3), Bit 28 - 35 Temperature (12), Bit 36-39 Zero
  3993. Log3 $name, 5, "$name: WS7053 after: " . substr($new_msg,0,4) ." ". substr($new_msg,4,4) ." ". substr($new_msg,8,4) ." ". substr($new_msg,12,4) ." ". substr($new_msg,16,4) ." ". substr($new_msg,20,4) ." ". substr($new_msg,24,4) ." ". substr($new_msg,28,4) ." ". substr($new_msg,32,4) ." ". substr($new_msg,36,4);
  3994. return (1,split("",$new_msg));
  3995. }
  3996. }
  3997. }
  3998. # manchester method
  3999. sub SIGNALduino_MCTFA
  4000. {
  4001. my ($name,$bitData,$id,$mcbitnum) = @_;
  4002. my $preamble_pos;
  4003. my $message_end;
  4004. my $message_length;
  4005. #if ($bitData =~ m/^.?(1){16,24}0101/) {
  4006. if ($bitData =~ m/(1{10}101)/ )
  4007. {
  4008. $preamble_pos=$+[1];
  4009. Log3 $name, 4, "$name: TFA 30.3208.0 preamble_pos = $preamble_pos";
  4010. return return (-1," sync not found") if ($preamble_pos <=0);
  4011. my @messages;
  4012. do
  4013. {
  4014. $message_end = index($bitData,"1111111111101",$preamble_pos);
  4015. if ($message_end < $preamble_pos)
  4016. {
  4017. $message_end=length($bitData);
  4018. }
  4019. $message_length = ($message_end - $preamble_pos);
  4020. my $part_str=substr($bitData,$preamble_pos,$message_length);
  4021. $part_str = substr($part_str,0,52) if (length($part_str)) > 52;
  4022. Log3 $name, 4, "$name: TFA message start=$preamble_pos end=$message_end with length".$message_length;
  4023. Log3 $name, 5, "$name: part $part_str";
  4024. my $hex=SIGNALduino_b2h($part_str);
  4025. push (@messages,$hex);
  4026. Log3 $name, 4, "$name: ".$hex;
  4027. $preamble_pos=index($bitData,"1101",$message_end)+4;
  4028. } while ( $message_end < length($bitData) );
  4029. my %seen;
  4030. my @dupmessages = map { 1==$seen{$_}++ ? $_ : () } @messages;
  4031. if (scalar(@dupmessages) > 0 ) {
  4032. Log3 $name, 4, "$name: repeated hex ".$dupmessages[0]." found ".$seen{$dupmessages[0]}." times";
  4033. return (1,$dupmessages[0]);
  4034. } else {
  4035. return (-1," no duplicate found");
  4036. }
  4037. }
  4038. return (-1,undef);
  4039. }
  4040. sub SIGNALduino_OSV2()
  4041. {
  4042. my ($name,$bitData,$id,$mcbitnum) = @_;
  4043. my $preamble_pos;
  4044. my $message_end;
  4045. my $message_length;
  4046. #$bitData =~ tr/10/01/;
  4047. if ($bitData =~ m/^.?(01){12,17}.?10011001/)
  4048. { # Valid OSV2 detected!
  4049. #$preamble_pos=index($bitData,"10011001",24);
  4050. $preamble_pos=$+[1];
  4051. Log3 $name, 4, "$name: OSV2 protocol detected: preamble_pos = $preamble_pos";
  4052. return return (-1," sync not found") if ($preamble_pos <=24);
  4053. $message_end=$-[1] if ($bitData =~ m/^.{44,}(01){16,17}.?10011001/); #Todo regex .{44,} 44 should be calculated from $preamble_pos+ min message lengh (44)
  4054. if (!defined($message_end) || $message_end < $preamble_pos) {
  4055. $message_end = length($bitData);
  4056. } else {
  4057. $message_end += 16;
  4058. Log3 $name, 4, "$name: OSV2 message end pattern found at pos $message_end lengthBitData=".length($bitData);
  4059. }
  4060. $message_length = ($message_end - $preamble_pos)/2;
  4061. return (-1," message is to short") if (defined($ProtocolListSIGNALduino{$id}{length_min}) && $message_length < $ProtocolListSIGNALduino{$id}{length_min} );
  4062. return (-1," message is to long") if (defined($ProtocolListSIGNALduino{$id}{length_max}) && $message_length > $ProtocolListSIGNALduino{$id}{length_max} );
  4063. my $idx=0;
  4064. my $osv2bits="";
  4065. my $osv2hex ="";
  4066. for ($idx=$preamble_pos;$idx<$message_end;$idx=$idx+16)
  4067. {
  4068. if ($message_end-$idx < 8 )
  4069. {
  4070. last;
  4071. }
  4072. my $osv2byte = "";
  4073. $osv2byte=NULL;
  4074. $osv2byte=substr($bitData,$idx,16);
  4075. my $rvosv2byte="";
  4076. for (my $p=0;$p<length($osv2byte);$p=$p+2)
  4077. {
  4078. $rvosv2byte = substr($osv2byte,$p,1).$rvosv2byte;
  4079. }
  4080. $rvosv2byte =~ tr/10/01/;
  4081. if (length($rvosv2byte) eq 8) {
  4082. $osv2hex=$osv2hex.sprintf('%02X', oct("0b$rvosv2byte")) ;
  4083. } else {
  4084. $osv2hex=$osv2hex.sprintf('%X', oct("0b$rvosv2byte")) ;
  4085. }
  4086. $osv2bits = $osv2bits.$rvosv2byte;
  4087. }
  4088. $osv2hex = sprintf("%02X", length($osv2hex)*4).$osv2hex;
  4089. Log3 $name, 4, "$name: OSV2 protocol converted to hex: ($osv2hex) with length (".(length($osv2hex)*4).") bits";
  4090. #$found=1;
  4091. #$dmsg=$osv2hex;
  4092. return (1,$osv2hex);
  4093. }
  4094. elsif ($bitData =~ m/^.?(1){16,24}0101/) { # Valid OSV3 detected!
  4095. $preamble_pos = index($bitData, '0101', 16);
  4096. $message_end = length($bitData);
  4097. $message_length = $message_end - ($preamble_pos+4);
  4098. Log3 $name, 4, "$name: OSV3 protocol detected: preamble_pos = $preamble_pos, message_length = $message_length";
  4099. my $idx=0;
  4100. #my $osv3bits="";
  4101. my $osv3hex ="";
  4102. for ($idx=$preamble_pos+4;$idx<length($bitData);$idx=$idx+4)
  4103. {
  4104. if (length($bitData)-$idx < 4 )
  4105. {
  4106. last;
  4107. }
  4108. my $osv3nibble = "";
  4109. $osv3nibble=NULL;
  4110. $osv3nibble=substr($bitData,$idx,4);
  4111. my $rvosv3nibble="";
  4112. for (my $p=0;$p<length($osv3nibble);$p++)
  4113. {
  4114. $rvosv3nibble = substr($osv3nibble,$p,1).$rvosv3nibble;
  4115. }
  4116. $osv3hex=$osv3hex.sprintf('%X', oct("0b$rvosv3nibble"));
  4117. #$osv3bits = $osv3bits.$rvosv3nibble;
  4118. }
  4119. Log3 $name, 4, "$name: OSV3 protocol = $osv3hex";
  4120. my $korr = 10;
  4121. # Check if nibble 1 is A
  4122. if (substr($osv3hex,1,1) ne 'A')
  4123. {
  4124. my $n1=substr($osv3hex,1,1);
  4125. $korr = hex(substr($osv3hex,3,1));
  4126. substr($osv3hex,1,1,'A'); # nibble 1 = A
  4127. substr($osv3hex,3,1,$n1); # nibble 3 = nibble1
  4128. }
  4129. # Korrektur nibble
  4130. my $insKorr = sprintf('%X', $korr);
  4131. # Check for ending 00
  4132. if (substr($osv3hex,-2,2) eq '00')
  4133. {
  4134. #substr($osv3hex,1,-2); # remove 00 at end
  4135. $osv3hex = substr($osv3hex, 0, length($osv3hex)-2);
  4136. }
  4137. my $osv3len = length($osv3hex);
  4138. $osv3hex .= '0';
  4139. my $turn0 = substr($osv3hex,5, $osv3len-4);
  4140. my $turn = '';
  4141. for ($idx=0; $idx<$osv3len-5; $idx=$idx+2) {
  4142. $turn = $turn . substr($turn0,$idx+1,1) . substr($turn0,$idx,1);
  4143. }
  4144. $osv3hex = substr($osv3hex,0,5) . $insKorr . $turn;
  4145. $osv3hex = substr($osv3hex,0,$osv3len+1);
  4146. $osv3hex = sprintf("%02X", length($osv3hex)*4).$osv3hex;
  4147. Log3 $name, 4, "$name: OSV3 protocol converted to hex: ($osv3hex) with length (".((length($osv3hex)-2)*4).") bits";
  4148. #$found=1;
  4149. #$dmsg=$osv2hex;
  4150. return (1,$osv3hex);
  4151. }
  4152. return (-1,undef);
  4153. }
  4154. sub SIGNALduino_OSV1()
  4155. {
  4156. my ($name,$bitData,$id,$mcbitnum) = @_;
  4157. return (-1," message is to short") if (defined($ProtocolListSIGNALduino{$id}{length_min}) && $mcbitnum < $ProtocolListSIGNALduino{$id}{length_min} );
  4158. return (-1," message is to long") if (defined($ProtocolListSIGNALduino{$id}{length_max}) && $mcbitnum > $ProtocolListSIGNALduino{$id}{length_max} );
  4159. my $calcsum = oct( "0b" . reverse substr($bitData,0,8));
  4160. $calcsum += oct( "0b" . reverse substr($bitData,8,8));
  4161. $calcsum += oct( "0b" . reverse substr($bitData,16,8));
  4162. $calcsum = ($calcsum & 0xFF) + ($calcsum >> 8);
  4163. my $checksum = oct( "0b" . reverse substr($bitData,24,8));
  4164. if ($calcsum != $checksum) { # Checksum
  4165. return (-1,"OSV1 - ERROR checksum not equal: $calcsum != $checksum");
  4166. } else {
  4167. Log3 $name, 4, "$name: OSV1 input data: $bitData";
  4168. my $newBitData = "00001010"; # Byte 0: Id1 = 0x0A
  4169. $newBitData .= "01001101"; # Byte 1: Id2 = 0x4D
  4170. # Todo: Sensortyp automtisch erkennen und Premable damit setzen.
  4171. # preamble => '50B208', # THR128 ohne Checksumme
  4172. # 50 - Length
  4173. # B2 - Byte 0: Id1
  4174. # 08 - Byte 1: Id2
  4175. my $channel = substr($bitData,6,2); # Byte 2 h: Channel
  4176. if ($channel == "00") { # in 0 LSB first
  4177. $newBitData .= "0001"; # out 1 MSB first
  4178. } elsif ($channel == "10") { # in 4 LSB first
  4179. $newBitData .= "0010"; # out 2 MSB first
  4180. } else { # in 8 LSB first
  4181. $newBitData .= "0100"; # out 4 MSB first
  4182. }
  4183. $newBitData .= "0000"; # Byte 2 l: ????
  4184. $newBitData .= "0000"; # Byte 3 h: address
  4185. $newBitData .= reverse substr($bitData,0,4); # Byte 3 l: address (Rolling Code)
  4186. $newBitData .= reverse substr($bitData,8,4); # Byte 4 h: T 0,1
  4187. $newBitData .= "0" . substr($bitData,23,1) . "00"; # Byte 4 l: Bit 2 - Batterie 0=ok, 1=low (< 2,5 Volt)
  4188. $newBitData .= reverse substr($bitData,16,4); # Byte 5 h: T 10
  4189. $newBitData .= reverse substr($bitData,12,4); # Byte 5 l: T 1
  4190. $newBitData .= "0000"; # Byte 6 h: immer 0000
  4191. $newBitData .= substr($bitData,21,1) . "000"; # Byte 6 l: Bit 3 - Temperatur 0=pos | 1=neg, Rest 0
  4192. $newBitData .= "00000000"; # Byte 7: immer 0000 0000
  4193. # calculate new checksum over first 16 nibbles
  4194. $checksum = 0;
  4195. for (my $i = 0; $i < 64; $i = $i + 4) {
  4196. $checksum += oct( "0b" . substr($newBitData, $i, 4));
  4197. }
  4198. $checksum = ($checksum - 0xa) & 0xff;
  4199. $newBitData .= sprintf("%08b",$checksum); # Byte 8: new Checksum
  4200. $newBitData .= "00000000"; # Byte 9: immer 0000 0000
  4201. my $osv1hex = "50" . SIGNALduino_b2h($newBitData); # output with length before #todo: Länge berechnen
  4202. Log3 $name, 4, "$name: OSV1 protocol id ($id) translated to RFXSensor format";
  4203. Log3 $name, 4, "$name: converted to hex: ($osv1hex)";
  4204. return (1,$osv1hex);
  4205. }
  4206. }
  4207. sub SIGNALduino_AS()
  4208. {
  4209. my ($name,$bitData,$id,$mcbitnum) = @_;
  4210. my $debug = AttrVal($name,"debug",0);
  4211. if(index($bitData,"1100",16) >= 0) # $rawData =~ m/^A{2,3}/)
  4212. { # Valid AS detected!
  4213. my $message_start = index($bitData,"1100",16);
  4214. Debug "$name: AS protocol detected \n" if ($debug);
  4215. my $message_end=index($bitData,"1100",$message_start+16);
  4216. $message_end = length($bitData) if ($message_end == -1);
  4217. my $message_length = $message_end - $message_start;
  4218. return (-1," message is to short") if (defined($ProtocolListSIGNALduino{$id}{length_min}) && $message_length < $ProtocolListSIGNALduino{$id}{length_min} );
  4219. return (-1," message is to long") if (defined($ProtocolListSIGNALduino{$id}{length_max}) && $message_length > $ProtocolListSIGNALduino{$id}{length_max} );
  4220. my $msgbits =substr($bitData,$message_start);
  4221. my $ashex=sprintf('%02X', oct("0b$msgbits"));
  4222. Log3 $name, 5, "$name: AS protocol converted to hex: ($ashex) with length ($message_length) bits \n";
  4223. return (1,$bitData);
  4224. }
  4225. return (-1,undef);
  4226. }
  4227. sub SIGNALduino_Hideki()
  4228. {
  4229. my ($name,$bitData,$id,$mcbitnum) = @_;
  4230. my $debug = AttrVal($name,"debug",0);
  4231. Debug "$name: search in $bitData \n" if ($debug);
  4232. my $message_start = index($bitData,"10101110");
  4233. my $invert = 0;
  4234. if ($message_start < 0) {
  4235. $bitData =~ tr/01/10/; # invert message
  4236. $message_start = index($bitData,"10101110"); # 0x75 but in reverse order
  4237. $invert = 1;
  4238. }
  4239. if ($message_start >= 0 ) # 0x75 but in reverse order
  4240. {
  4241. Debug "$name: Hideki protocol (invert=$invert) detected \n" if ($debug);
  4242. # Todo: Mindest Laenge fuer startpunkt vorspringen
  4243. # Todo: Wiederholung auch an das Modul weitergeben, damit es dort geprueft werden kann
  4244. my $message_end = index($bitData,"10101110",$message_start+71); # pruefen auf ein zweites 0x75, mindestens 72 bit nach 1. 0x75, da der Regensensor minimum 8 Byte besitzt je byte haben wir 9 bit
  4245. $message_end = length($bitData) if ($message_end == -1);
  4246. my $message_length = $message_end - $message_start;
  4247. return (-1,"message is to short") if (defined($ProtocolListSIGNALduino{$id}{length_min}) && $message_length < $ProtocolListSIGNALduino{$id}{length_min} );
  4248. return (-1,"message is to long") if (defined($ProtocolListSIGNALduino{$id}{length_max}) && $message_length > $ProtocolListSIGNALduino{$id}{length_max} );
  4249. my $hidekihex;
  4250. my $idx;
  4251. for ($idx=$message_start; $idx<$message_end; $idx=$idx+9)
  4252. {
  4253. my $byte = "";
  4254. $byte= substr($bitData,$idx,8); ## Ignore every 9th bit
  4255. Debug "$name: byte in order $byte " if ($debug);
  4256. $byte = scalar reverse $byte;
  4257. Debug "$name: byte reversed $byte , as hex: ".sprintf('%X', oct("0b$byte"))."\n" if ($debug);
  4258. $hidekihex=$hidekihex.sprintf('%02X', oct("0b$byte"));
  4259. }
  4260. if ($invert == 0) {
  4261. SIGNALduino_Log3 $name, 4, "$name: receive Hideki protocol not inverted";
  4262. } else {
  4263. SIGNALduino_Log3 $name, 4, "$name: receive Hideki protocol inverted";
  4264. }
  4265. SIGNALduino_Log3 $name, 4, "$name: Hideki protocol converted to hex: $hidekihex with " .$message_length ." bits, messagestart $message_start";
  4266. return (1,$hidekihex); ## Return only the original bits, include length
  4267. }
  4268. SIGNALduino_Log3 $name, 4, "$name: hideki start pattern (10101110) not found";
  4269. return (-1,"Start pattern (10101110) not found");
  4270. }
  4271. sub SIGNALduino_Maverick()
  4272. {
  4273. my ($name,$bitData,$id,$mcbitnum) = @_;
  4274. my $debug = AttrVal($name,"debug",0);
  4275. if ($bitData =~ m/^.*(101010101001100110010101).*/)
  4276. { # Valid Maverick header detected
  4277. my $header_pos=$+[1];
  4278. Log3 $name, 4, "$name: Maverick protocol detected: header_pos = $header_pos";
  4279. my $hex=SIGNALduino_b2h(substr($bitData,$header_pos,26*4));
  4280. return (1,$hex); ## Return the bits unchanged in hex
  4281. } else {
  4282. return return (-1," header not found");
  4283. }
  4284. }
  4285. sub SIGNALduino_OSPIR()
  4286. {
  4287. my ($name,$bitData,$id,$mcbitnum) = @_;
  4288. my $debug = AttrVal($name,"debug",0);
  4289. if ($bitData =~ m/^.*(1{14}|0{14}).*/)
  4290. { # Valid Oregon PIR detected
  4291. my $header_pos=$+[1];
  4292. Log3 $name, 4, "$name: Oregon PIR protocol detected: header_pos = $header_pos";
  4293. my $hex=SIGNALduino_b2h($bitData);
  4294. return (1,$hex); ## Return the bits unchanged in hex
  4295. } else {
  4296. return return (-1," header not found");
  4297. }
  4298. }
  4299. sub SIGNALduino_MCRAW()
  4300. {
  4301. my ($name,$bitData,$id,$mcbitnum) = @_;
  4302. my $debug = AttrVal($name,"debug",0);
  4303. my $hex=SIGNALduino_b2h($bitData);
  4304. return (1,$hex); ## Return the bits unchanged in hex
  4305. }
  4306. sub SIGNALduino_SomfyRTS()
  4307. {
  4308. my ($name, $bitData,$id,$mcbitnum) = @_;
  4309. #(my $negBits = $bitData) =~ tr/10/01/; # Todo: eventuell auf pack umstellen
  4310. if (defined($mcbitnum)) {
  4311. Log3 $name, 4, "$name: Somfy bitdata: $bitData ($mcbitnum)";
  4312. if ($mcbitnum == 57) {
  4313. $bitData = substr($bitData, 1, 56);
  4314. Log3 $name, 4, "$name: Somfy bitdata: _$bitData (" . length($bitData) . "). Bit am Anfang entfernt";
  4315. }
  4316. }
  4317. my $encData = SIGNALduino_b2h($bitData);
  4318. #Log3 $name, 4, "$name: Somfy RTS protocol enc: $encData";
  4319. return (1, $encData);
  4320. }
  4321. # - - - - - - - - - - - -
  4322. #=item SIGNALduino_filterMC()
  4323. #This functons, will act as a filter function. It will decode MU data via Manchester encoding
  4324. #
  4325. # Will return $count of ???, modified $rawData , modified %patternListRaw,
  4326. # =cut
  4327. sub SIGNALduino_filterMC($$$%)
  4328. {
  4329. ## Warema Implementierung : Todo variabel gestalten
  4330. my ($name,$id,$rawData,%patternListRaw) = @_;
  4331. my $debug = AttrVal($name,"debug",0);
  4332. my ($ht, $hasbit, $value) = 0;
  4333. $value=1 if (!$debug);
  4334. my @bitData;
  4335. my @sigData = split "",$rawData;
  4336. foreach my $pulse (@sigData)
  4337. {
  4338. next if (!defined($patternListRaw{$pulse}));
  4339. #Log3 $name, 4, "$name: pulese: ".$patternListRaw{$pulse};
  4340. if (SIGNALduino_inTol($ProtocolListSIGNALduino{$id}{clockabs},abs($patternListRaw{$pulse}),$ProtocolListSIGNALduino{$id}{clockabs}*0.5))
  4341. {
  4342. # Short
  4343. $hasbit=$ht;
  4344. $ht = $ht ^ 0b00000001;
  4345. $value='S' if($debug);
  4346. #Log3 $name, 4, "$name: filter S ";
  4347. } elsif ( SIGNALduino_inTol($ProtocolListSIGNALduino{$id}{clockabs}*2,abs($patternListRaw{$pulse}),$ProtocolListSIGNALduino{$id}{clockabs}*0.5)) {
  4348. # Long
  4349. $hasbit=1;
  4350. $ht=1;
  4351. $value='L' if($debug);
  4352. #Log3 $name, 4, "$name: filter L ";
  4353. } elsif ( SIGNALduino_inTol($ProtocolListSIGNALduino{$id}{syncabs}+(2*$ProtocolListSIGNALduino{$id}{clockabs}),abs($patternListRaw{$pulse}),$ProtocolListSIGNALduino{$id}{clockabs}*0.5)) {
  4354. $hasbit=1;
  4355. $ht=1;
  4356. $value='L' if($debug);
  4357. #Log3 $name, 4, "$name: sync L ";
  4358. } else {
  4359. # No Manchester Data
  4360. $ht=0;
  4361. $hasbit=0;
  4362. #Log3 $name, 4, "$name: filter n ";
  4363. }
  4364. if ($hasbit && $value) {
  4365. $value = lc($value) if($debug && $patternListRaw{$pulse} < 0);
  4366. my $bit=$patternListRaw{$pulse} > 0 ? 1 : 0;
  4367. #Log3 $name, 5, "$name: adding value: ".$bit;
  4368. push @bitData, $bit ;
  4369. }
  4370. }
  4371. my %patternListRawFilter;
  4372. $patternListRawFilter{0} = 0;
  4373. $patternListRawFilter{1} = $ProtocolListSIGNALduino{$id}{clockabs};
  4374. #Log3 $name, 5, "$name: filterbits: ".@bitData;
  4375. $rawData = join "", @bitData;
  4376. return (undef ,$rawData, %patternListRawFilter);
  4377. }
  4378. # - - - - - - - - - - - -
  4379. #=item SIGNALduino_filterSign()
  4380. #This functons, will act as a filter function. It will remove the sign from the pattern, and compress message and pattern
  4381. #
  4382. # Will return $count of combined values, modified $rawData , modified %patternListRaw,
  4383. # =cut
  4384. sub SIGNALduino_filterSign($$$%)
  4385. {
  4386. my ($name,$id,$rawData,%patternListRaw) = @_;
  4387. my $debug = AttrVal($name,"debug",0);
  4388. my %buckets;
  4389. # Remove Sign
  4390. %patternListRaw = map { $_ => abs($patternListRaw{$_})} keys %patternListRaw; ## remove sign from all
  4391. my $intol=0;
  4392. my $cnt=0;
  4393. # compress pattern hash
  4394. foreach my $key (keys %patternListRaw) {
  4395. #print "chk:".$patternListRaw{$key};
  4396. #print "\n";
  4397. $intol=0;
  4398. foreach my $b_key (keys %buckets){
  4399. #print "with:".$buckets{$b_key};
  4400. #print "\n";
  4401. # $value - $set <= $tolerance
  4402. if (SIGNALduino_inTol($patternListRaw{$key},$buckets{$b_key},$buckets{$b_key}*0.25))
  4403. {
  4404. #print"\t". $patternListRaw{$key}."($key) is intol of ".$buckets{$b_key}."($b_key) \n";
  4405. $cnt++;
  4406. eval "\$rawData =~ tr/$key/$b_key/";
  4407. #if ($key == $msg_parts{clockidx})
  4408. #{
  4409. # $msg_pats{syncidx} = $buckets{$key};
  4410. # }
  4411. # elsif ($key == $msg_parts{syncidx})
  4412. # {
  4413. # $msg_pats{syncidx} = $buckets{$key};
  4414. # }
  4415. $buckets{$b_key} = ($buckets{$b_key} + $patternListRaw{$key}) /2;
  4416. #print"\t recalc to ". $buckets{$b_key}."\n";
  4417. delete ($patternListRaw{$key}); # deletes the compressed entry
  4418. $intol=1;
  4419. last;
  4420. }
  4421. }
  4422. if ($intol == 0) {
  4423. $buckets{$key}=abs($patternListRaw{$key});
  4424. }
  4425. }
  4426. return ($cnt,$rawData, %patternListRaw);
  4427. #print "rdata: ".$msg_parts{rawData}."\n";
  4428. #print Dumper (%buckets);
  4429. #print Dumper (%msg_parts);
  4430. #modify msg_parts pattern hash
  4431. #$patternListRaw = \%buckets;
  4432. }
  4433. # - - - - - - - - - - - -
  4434. #=item SIGNALduino_compPattern()
  4435. #This functons, will act as a filter function. It will remove the sign from the pattern, and compress message and pattern
  4436. #
  4437. # Will return $count of combined values, modified $rawData , modified %patternListRaw,
  4438. # =cut
  4439. sub SIGNALduino_compPattern($$$%)
  4440. {
  4441. my ($name,$id,$rawData,%patternListRaw) = @_;
  4442. my $debug = AttrVal($name,"debug",0);
  4443. my %buckets;
  4444. # Remove Sign
  4445. #%patternListRaw = map { $_ => abs($patternListRaw{$_})} keys %patternListRaw; ## remove sing from all
  4446. my $intol=0;
  4447. my $cnt=0;
  4448. # compress pattern hash
  4449. foreach my $key (keys %patternListRaw) {
  4450. #print "chk:".$patternListRaw{$key};
  4451. #print "\n";
  4452. $intol=0;
  4453. foreach my $b_key (keys %buckets){
  4454. #print "with:".$buckets{$b_key};
  4455. #print "\n";
  4456. # $value - $set <= $tolerance
  4457. if (SIGNALduino_inTol($patternListRaw{$key},$buckets{$b_key},$buckets{$b_key}*0.4))
  4458. {
  4459. #print"\t". $patternListRaw{$key}."($key) is intol of ".$buckets{$b_key}."($b_key) \n";
  4460. $cnt++;
  4461. eval "\$rawData =~ tr/$key/$b_key/";
  4462. #if ($key == $msg_parts{clockidx})
  4463. #{
  4464. # $msg_pats{syncidx} = $buckets{$key};
  4465. # }
  4466. # elsif ($key == $msg_parts{syncidx})
  4467. # {
  4468. # $msg_pats{syncidx} = $buckets{$key};
  4469. # }
  4470. $buckets{$b_key} = ($buckets{$b_key} + $patternListRaw{$key}) /2;
  4471. #print"\t recalc to ". $buckets{$b_key}."\n";
  4472. delete ($patternListRaw{$key}); # deletes the compressed entry
  4473. $intol=1;
  4474. last;
  4475. }
  4476. }
  4477. if ($intol == 0) {
  4478. $buckets{$key}=$patternListRaw{$key};
  4479. }
  4480. }
  4481. return ($cnt,$rawData, %patternListRaw);
  4482. #print "rdata: ".$msg_parts{rawData}."\n";
  4483. #print Dumper (%buckets);
  4484. #print Dumper (%msg_parts);
  4485. #modify msg_parts pattern hash
  4486. #$patternListRaw = \%buckets;
  4487. }
  4488. ################################################
  4489. # the new Log with integrated loglevel checking
  4490. sub SIGNALduino_Log3($$$)
  4491. {
  4492. my ($dev, $loglevel, $text) = @_;
  4493. return Log3($dev,$loglevel,$text);
  4494. }
  4495. #print Dumper (%msg_parts);
  4496. #print "\n";
  4497. #SIGNALduino_filterSign(%msg_parts);
  4498. #print Dumper (%msg_parts);
  4499. #print "\n";
  4500. 1;
  4501. =pod
  4502. =item summary supports the same low-cost receiver for digital signals
  4503. =item summary_DE Unterst&uumltzt den gleichnamigen Low-Cost Empf&aumlnger fuer digitale Signale
  4504. =begin html
  4505. <a name="SIGNALduino"></a>
  4506. <h3>SIGNALduino</h3>
  4507. <table>
  4508. <tr><td>
  4509. The SIGNALduino ia based on an idea from mdorenka published at <a
  4510. href="http://forum.fhem.de/index.php/topic,17196.0.html">FHEM Forum</a>.
  4511. With the opensource firmware (see this <a
  4512. href="https://github.com/RFD-FHEM/SIGNALduino">link</a>) it is capable
  4513. to receive and send different protocols over different medias. Currently are 433Mhz protocols implemented.
  4514. <br><br>
  4515. The following device support is currently available:
  4516. <br><br>
  4517. Wireless switches <br>
  4518. ITv1 & ITv3/Elro and other brands using pt2263 or arctech protocol--> uses IT.pm<br><br>
  4519. In the ITv1 protocol is used to sent a default ITclock from 250 and it may be necessary in the IT-Modul to define the attribute ITclock<br>
  4520. <br><br>
  4521. Temperatur / humidity senso
  4522. <ul>
  4523. <li>PEARL NC7159, LogiLink WS0002,GT-WT-02,AURIOL,TCM97001, TCM27 and many more -> 14_CUL_TCM97001 </li>
  4524. <li>Oregon Scientific v2 and v3 Sensors -> 41_OREGON.pm</li>
  4525. <li>Temperatur / humidity sensors suppored -> 14_SD_WS07</li>
  4526. <li>technoline WS 6750 and TX70DTH -> 14_SD_WS07</li>
  4527. <li>Eurochon EAS 800z -> 14_SD_WS07</li>
  4528. <li>CTW600, WH1080 -> 14_SD_WS09 </li>
  4529. <li>Hama TS33C, Bresser Thermo/Hygro Sensor -> 14_Hideki</li>
  4530. <li>FreeTec Aussenmodul NC-7344 -> 14_SD_WS07</li>
  4531. </ul>
  4532. <br><br>
  4533. It is possible to attach more than one device in order to get better
  4534. reception, fhem will filter out duplicate messages.<br><br>
  4535. Note: this module require the Device::SerialPort or Win32::SerialPort
  4536. module. It can currently only attatched via USB.
  4537. </td>
  4538. </tr>
  4539. </table>
  4540. <br>
  4541. <a name="SIGNALduinodefine"></a>
  4542. <b>Define</b><br>
  4543. <code>define &lt;name&gt; SIGNALduino &lt;device&gt; </code> <br>
  4544. <br>
  4545. USB-connected devices (SIGNALduino):<br>
  4546. <ul><li>
  4547. &lt;device&gt; specifies the serial port to communicate with the SIGNALduino.
  4548. The name of the serial-device depends on your distribution, under
  4549. linux the cdc_acm kernel module is responsible, and usually a
  4550. /dev/ttyACM0 or /dev/ttyUSB0 device will be created. If your distribution does not have a
  4551. cdc_acm module, you can force usbserial to handle the SIGNALduino by the
  4552. following command:
  4553. <ul>
  4554. modprobe usbserial
  4555. vendor=0x03eb
  4556. product=0x204b
  4557. </ul>In this case the device is most probably
  4558. /dev/ttyUSB0.<br><br>
  4559. You can also specify a baudrate if the device name contains the @
  4560. character, e.g.: /dev/ttyACM0@57600<br><br>This is also the default baudrate
  4561. It is recommended to specify the device via a name which does not change:
  4562. e.g. via by-id devicename: /dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0@57600
  4563. If the baudrate is "directio" (e.g.: /dev/ttyACM0@directio), then the
  4564. perl module Device::SerialPort is not needed, and fhem opens the device
  4565. with simple file io. This might work if the operating system uses sane
  4566. defaults for the serial parameters, e.g. some Linux distributions and
  4567. OSX. <br><br>
  4568. </li>
  4569. </ul>
  4570. <a name="SIGNALduinoattr"></a>
  4571. <b>Attributes</b>
  4572. <ul>
  4573. <li><a name="addvaltrigger">addvaltrigger</a><br>
  4574. Create triggers for additional device values. Right now these are RSSI, RAWMSG and DMSG.
  4575. </li>
  4576. <li>blacklist_IDs<br>
  4577. The blacklist works only if a whitelist not exist.
  4578. </li>
  4579. <li>cc1101_frequency<br>
  4580. Since the PA table values ​​are frequency-dependent, is at 868 MHz a value greater 800 required.
  4581. </li>
  4582. <li><a href="#do_not_notify">do_not_notify</a></li>
  4583. <li><a href="#attrdummy">dummy</a></li>
  4584. <li>debug<br>
  4585. This will bring the module in a very verbose debug output. Usefull to find new signals and verify if the demodulation works correctly.
  4586. </li>
  4587. <li>development<br>
  4588. With development you can enable protocol decoding for protocolls witch are still in development and may not be very accurate implemented.
  4589. This can result in crashes or throw high amount of log entrys in your logfile, so be careful to use this. <br><br>
  4590. Protocols flagged with a developID flag are not loaded unless specified to do so.<br>
  4591. If the flag developId => 'y' is set in the protocol defintion then the protocol is still in development. You can enable it with the attribute:<br>
  4592. Specify "y" followed with the protocol id to enable it.<br><br>
  4593. If the protocoll is developed well, but the logical module is not ready, developId => 'm' is set.<br>
  4594. You can enable it with the attribute:<br>
  4595. Specify "m" followed with the protocol id to enable it.<br>
  4596. </li>
  4597. <li>doubleMsgCheck_IDs<br>
  4598. This attribute allows it, to specify protocols which must be received two equal messages to call dispatch to the modules.<br>
  4599. You can specify multiple IDs wih a colon : 0,3,7,12<br>
  4600. </li>
  4601. <li>flashCommand<br>
  4602. This is the command, that is executed to performa the firmware flash. Do not edit, if you don't know what you are doing.<br>
  4603. The default is: avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]<br>
  4604. It contains some place-holders that automatically get filled with the according values:<br>
  4605. <ul>
  4606. <li>[PORT]<br>
  4607. is the port the Signalduino is connectd to (e.g. /dev/ttyUSB0) and will be used from the defenition</li>
  4608. <li>[HEXFILE]<br>
  4609. is the .hex file that shall get flashed. There are three options (applied in this order):<br>
  4610. - passed in set flash as first argument<br>
  4611. - taken from the hexFile attribute<br>
  4612. - the default value defined in the module<br>
  4613. </li>
  4614. <li>[LOGFILE]<br>
  4615. The logfile that collects information about the flash process. It gets displayed in FHEM after finishing the flash process</li>
  4616. </ul>
  4617. </li>
  4618. <li>hardware<br>
  4619. When using the flash command, you should specify what hardware you have connected to the usbport. Doing not, can cause failures of the device.
  4620. </li>
  4621. <li>minsecs<br>
  4622. This is a very special attribute. It is provided to other modules. minsecs should act like a threshold. All logic must be done in the logical module.
  4623. If specified, then supported modules will discard new messages if minsecs isn't past.
  4624. </li>
  4625. <li>noMsgVerbose<br>
  4626. With this attribute you can control the logging of debug messages from the io device.
  4627. If set to 3, this messages are logged if global verbose is set to 3 or higher.
  4628. </li>
  4629. <li>longids<br>
  4630. Comma separated list of device-types for SIGNALduino that should be handled using long IDs. This additional ID allows it to differentiate some weather sensors, if they are sending on the same channel. Therfor a random generated id is added. If you choose to use longids, then you'll have to define a different device after battery change.<br>
  4631. Default is to not to use long IDs for all devices.
  4632. <br><br>
  4633. Examples:<PRE>
  4634. # Do not use any long IDs for any devices:
  4635. attr sduino longids 0
  4636. # Use any long IDs for all devices (this is default):
  4637. attr sduino longids 1
  4638. # Use longids for BTHR918N devices.
  4639. # Will generate devices names like BTHR918N_f3.
  4640. attr sduino longids BTHR918N
  4641. </PRE></li>
  4642. <li>rawmsgEvent<br>
  4643. When set to "1" received raw messages triggers events
  4644. </li>
  4645. <li>suppressDeviceRawmsg<br>
  4646. When set to 1, the internal "RAWMSG" will not be updated with the received messages
  4647. </li>
  4648. <li>whitelistIDs<br>
  4649. This attribute allows it, to specify whichs protocos are considured from this module.
  4650. Protocols which are not considured, will not generate logmessages or events. They are then completly ignored.
  4651. This makes it possible to lower ressource usage and give some better clearnes in the logs.
  4652. You can specify multiple whitelistIDs wih a colon : 0,3,7,12<br>
  4653. With a # at the beginnging whitelistIDs can be deactivated.
  4654. </li><br>
  4655. <li>WS09_CRCAUS<br>
  4656. <br>0: CRC-Check WH1080 CRC = 0 on, default
  4657. <br>2: CRC = 49 (x031) WH1080, set OK
  4658. </li>
  4659. </ul>
  4660. <a name="SIGNALduinoget"></a>
  4661. <b>Get</b>
  4662. <ul>
  4663. <li>version<br>
  4664. return the SIGNALduino firmware version
  4665. </li><br>
  4666. <li>raw<br>
  4667. Issue a SIGNALduino firmware command, and wait for one line of data returned by
  4668. the SIGNALduino. See the SIGNALduino firmware code for details on SIGNALduino
  4669. commands. With this line, you can send almost any signal via a transmitter connected
  4670. </li><br>
  4671. <li>cmds<br>
  4672. Depending on the firmware installed, SIGNALduinos have a different set of
  4673. possible commands. Please refer to the sourcecode of the firmware of your
  4674. SIGNALduino to interpret the response of this command. See also the raw-
  4675. command.
  4676. </li><br>
  4677. <li>protocolIDs<br>
  4678. display a list of the protocol IDs
  4679. </li><br>
  4680. <li>ccconf<br>
  4681. Only with cc1101 receiver.
  4682. Read some CUL radio-chip (cc1101) registers (frequency, bandwidth, etc.),
  4683. and display them in human readable form.
  4684. </li><br>
  4685. <li>ccpatable<br>
  4686. read cc1101 PA table (power amplification for RF sending)
  4687. </li><br>
  4688. <li>ccreg<br>
  4689. read cc1101 registers (99 reads all cc1101 registers)
  4690. </li><br>
  4691. </ul>
  4692. <a name="SIGNALduinoset"></a>
  4693. <b>SET</b>
  4694. <ul>
  4695. <li>raw<br>
  4696. Issue a SIGNALduino firmware command, without waiting data returned by
  4697. the SIGNALduino. See the SIGNALduino firmware code for details on SIGNALduino
  4698. commands. With this line, you can send almost any signal via a transmitter connected
  4699. To send some raw data look at these examples:
  4700. P<protocol id>#binarydata#R<num of repeats>#C<optional clock> (#C is optional)
  4701. <br>Example 1: set sduino raw SR;R=3;P0=500;P1=-9000;P2=-4000;P3=-2000;D=0302030 sends the data in raw mode 3 times repeated
  4702. <br>Example 2: set sduino raw SM;R=3;P0=500;C=250;D=A4F7FDDE sends the data manchester encoded with a clock of 250uS
  4703. <br>Example 3: set sduino raw SC;R=3;SR;P0=5000;SM;P0=500;C=250;D=A4F7FDDE sends a combined message of raw and manchester encoded repeated 3 times
  4704. <br>;
  4705. </p>
  4706. </li><br>
  4707. <li>reset<br>
  4708. This will do a reset of the usb port and normaly causes to reset the uC connected.
  4709. </li><br>
  4710. <li>close<br>
  4711. Closes the connection to the device.
  4712. </li><br>
  4713. <li>flash [hexFile|url]<br>
  4714. The SIGNALduino needs the right firmware to be able to receive and deliver the sensor data to fhem. In addition to the way using the
  4715. arduino IDE to flash the firmware into the SIGNALduino this provides a way to flash it directly from FHEM.
  4716. You can specify a file on your fhem server or specify a url from which the firmware is downloaded
  4717. There are some requirements:
  4718. <ul>
  4719. <li>avrdude must be installed on the host<br>
  4720. On a Raspberry PI this can be done with: sudo apt-get install avrdude</li>
  4721. <li>the hardware attribute must be set if using any other hardware as an Arduino nano<br>
  4722. This attribute defines the command, that gets sent to avrdude to flash the uC.<br></li>
  4723. <br>
  4724. </ul>
  4725. </li>
  4726. <li>sendMsg<br>
  4727. This command will create the needed instructions for sending raw data via the signalduino. Insteaf of specifying the signaldata by your own you specify
  4728. a protocol and the bits you want to send. The command will generate the needed command, that the signalduino will send this.
  4729. <br><br>
  4730. Please note, that this command will work only for MU or MS protocols. You can't transmit manchester data this way.
  4731. <br><br>
  4732. Input args are:
  4733. <p>
  4734. P<protocol id>#binarydata#R<num of repeats>#C<optional clock> (#C is optional)
  4735. <br>Example: P0#0101#R3#C500
  4736. <br>Will generate the raw send command for the message 0101 with protocol 0 and instruct the arduino to send this three times and the clock is 500.
  4737. <br>SR;R=3;P0=500;P1=-9000;P2=-4000;P3=-2000;D=03020302;
  4738. </p>
  4739. </li><br>
  4740. <li>enableMessagetype<br>
  4741. Allows you to enable the message processing for
  4742. <ul>
  4743. <li>messages with sync (syncedMS),</li>
  4744. <li>messages without a sync pulse (unsyncedMU) </li>
  4745. <li>manchester encoded messages (manchesterMC) </li>
  4746. </ul>
  4747. The new state will be saved into the eeprom of your arduino.
  4748. </li><br>
  4749. <li>disableMessagetype<br>
  4750. Allows you to disable the message processing for
  4751. <ul>
  4752. <li>messages with sync (syncedMS),</li>
  4753. <li>messages without a sync pulse (unsyncedMU)</li>
  4754. <li>manchester encoded messages (manchesterMC) </li>
  4755. </ul>
  4756. The new state will be saved into the eeprom of your arduino.
  4757. </li><br><br>
  4758. <li>freq / bWidth / patable / rAmpl / sens<br>
  4759. Only with CC1101 receiver.<br>
  4760. Set the sduino frequency / bandwidth / PA table / receiver-amplitude / sensitivity<br>
  4761. Use it with care, it may destroy your hardware and it even may be
  4762. illegal to do so. Note: The parameters used for RFR transmission are
  4763. not affected.<br>
  4764. <ul>
  4765. <li>freq sets both the reception and transmission frequency. Note:
  4766. Although the CC1101 can be set to frequencies between 315 and 915
  4767. MHz, the antenna interface and the antenna of the CUL is tuned for
  4768. exactly one frequency. Default is 868.3 MHz (or 433 MHz)</li>
  4769. <li>bWidth can be set to values between 58 kHz and 812 kHz. Large values
  4770. are susceptible to interference, but make possible to receive
  4771. inaccurately calibrated transmitters. It affects tranmission too.
  4772. Default is 325 kHz.</li>
  4773. <li>patable change the PA table (power amplification for RF sending)
  4774. </li>
  4775. <li>rAmpl is receiver amplification, with values between 24 and 42 dB.
  4776. Bigger values allow reception of weak signals. Default is 42.
  4777. </li>
  4778. <li>sens is the decision boundary between the on and off values, and it
  4779. is 4, 8, 12 or 16 dB. Smaller values allow reception of less clear
  4780. signals. Default is 4 dB.</li>
  4781. </ul>
  4782. </li><br>
  4783. </ul>
  4784. =end html
  4785. =cut