00_SIGNALduino.pm 182 KB

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