| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465 |
- ##############################################
- # $Id: 00_SIGNALduino.pm 16390 2018-03-11 22:22:56Z Sidey $
- #
- # v3.3.2 (stable release 3.3)
- # The module is inspired by the FHEMduino project and modified in serval ways for processing the incomming messages
- # see http://www.fhemwiki.de/wiki/SIGNALDuino
- # It was modified also to provide support for raw message handling which can be send from the SIGNALduino
- # The purpos is to use it as addition to the SIGNALduino which runs on an arduno nano or arduino uno.
- # It routes Messages serval Modules which are already integrated in FHEM. But there are also modules which comes with it.
- # N. Butzek, S. Butzek, 2014-2015
- # S.Butzek,Ralf9 2016-2017
- package main;
- use strict;
- use warnings;
- use Time::HiRes qw(gettimeofday);
- use Data::Dumper qw(Dumper);
- use Scalar::Util qw(looks_like_number);
- no warnings 'portable';
- #use POSIX qw( floor); # can be removed
- #use Math::Round qw();
- use constant {
- SDUINO_VERSION => "v3.3.2",
- SDUINO_INIT_WAIT_XQ => 1.5, # wait disable device
- SDUINO_INIT_WAIT => 2,
- SDUINO_INIT_MAXRETRY => 3,
- SDUINO_CMD_TIMEOUT => 10,
- SDUINO_KEEPALIVE_TIMEOUT => 60,
- SDUINO_KEEPALIVE_MAXRETRY => 3,
- SDUINO_WRITEQUEUE_NEXT => 0.3,
- SDUINO_WRITEQUEUE_TIMEOUT => 2,
-
- SDUINO_DISPATCH_VERBOSE => 5, # default 5
- };
- sub SIGNALduino_Attr(@);
- #sub SIGNALduino_Clear($); # wird nicht mehr benoetigt
- sub SIGNALduino_HandleWriteQueue($);
- sub SIGNALduino_Parse($$$$@);
- sub SIGNALduino_Read($);
- #sub SIGNALduino_ReadAnswer($$$$); # wird nicht mehr benoetigt
- sub SIGNALduino_Ready($);
- sub SIGNALduino_Write($$$);
- sub SIGNALduino_SimpleWrite(@);
- #my $debug=0;
- my %gets = ( # Name, Data to send to the SIGNALduino, Regexp for the answer
- "version" => ["V", 'V\s.*SIGNAL(duino|ESP).*'],
- "freeram" => ["R", '^[0-9]+'],
- "raw" => ["", '.*'],
- "uptime" => ["t", '^[0-9]+' ],
- "cmds" => ["?", '.*Use one of[ 0-9A-Za-z]+[\r\n]*$' ],
- # "ITParms" => ["ip",'.*'],
- "ping" => ["P",'^OK$'],
- "config" => ["CG",'^MS.*MU.*MC.*'],
- "protocolIDs" => ["none",'none'],
- "ccconf" => ["C0DnF", 'C0Dn11.*'],
- "ccreg" => ["C", '^C.* = .*'],
- "ccpatable" => ["C3E", '^C3E = .*'],
- # "ITClock" => ["ic", '\d+'],
- # "FAParms" => ["fp", '.*' ],
- # "TCParms" => ["dp", '.*' ],
- # "HXParms" => ["hp", '.*' ]
- );
- my %sets = (
- "raw" => '',
- "flash" => '',
- "reset" => 'noArg',
- "close" => 'noArg',
- #"disablereceiver" => "",
- #"ITClock" => 'slider,100,20,700',
- "enableMessagetype" => 'syncedMS,unsyncedMU,manchesterMC',
- "disableMessagetype" => 'syncedMS,unsyncedMU,manchesterMC',
- "sendMsg" => "",
- "cc1101_freq" => '',
- "cc1101_bWidth" => '',
- "cc1101_rAmpl" => '',
- "cc1101_sens" => '',
- "cc1101_patable_433" => '-10_dBm,-5_dBm,0_dBm,5_dBm,7_dBm,10_dBm',
- "cc1101_patable_868" => '-10_dBm,-5_dBm,0_dBm,5_dBm,7_dBm,10_dBm',
- );
- my %patable = (
- "433" =>
- {
- "-10_dBm" => '34',
- "-5_dBm" => '68',
- "0_dBm" => '60',
- "5_dBm" => '84',
- "7_dBm" => 'C8',
- "10_dBm" => 'C0',
- },
- "868" =>
- {
- "-10_dBm" => '27',
- "-5_dBm" => '67',
- "0_dBm" => '50',
- "5_dBm" => '81',
- "7_dBm" => 'CB',
- "10_dBm" => 'C2',
- },
- );
- my @ampllist = (24, 27, 30, 33, 36, 38, 40, 42); # rAmpl(dB)
- ## Supported Clients per default
- my $clientsSIGNALduino = ":IT:"
- ."CUL_TCM97001:"
- ."SD_RSL:"
- ."OREGON:"
- ."CUL_TX:"
- ."SD_AS:"
- ."Hideki:"
- ."SD_WS07:"
- ."SD_WS09:"
- ." :" # Zeilenumbruch
- ."SD_WS:"
- ."RFXX10REC:"
- ."Dooya:"
- ."SOMFY:"
- ."SD_UT:" ## BELL 201.2 TXA
- ."SD_WS_Maverick:"
- ."FLAMINGO:"
- ."CUL_WS:"
- ."Revolt:"
- ." :" # Zeilenumbruch
- ."FS10:"
- ."CUL_FHTTK:"
- ."Siro:"
- ."FHT:"
- ."FS20:"
- ."SIGNALduino_un:"
- ;
- ## default regex match List for dispatching message to logical modules, can be updated during runtime because it is referenced
- my %matchListSIGNALduino = (
- "1:IT" => "^i......", # Intertechno Format
- "2:CUL_TCM97001" => "^s[A-Fa-f0-9]+", # Any hex string beginning with s
- "3:SD_RSL" => "^P1#[A-Fa-f0-9]{8}",
- "5:CUL_TX" => "^TX..........", # Need TX to avoid FHTTK
- "6:SD_AS" => "^P2#[A-Fa-f0-9]{7,8}", # Arduino based Sensors, should not be default
- "4:OREGON" => "^(3[8-9A-F]|[4-6][0-9A-F]|7[0-8]).*",
- "7:Hideki" => "^P12#75[A-F0-9]+",
- "9:CUL_FHTTK" => "^T[A-F0-9]{8}",
- "10:SD_WS07" => "^P7#[A-Fa-f0-9]{6}F[A-Fa-f0-9]{2}(#R[A-F0-9][A-F0-9]){0,1}\$",
- "11:SD_WS09" => "^P9#F[A-Fa-f0-9]+",
- "12:SD_WS" => '^W\d+x{0,1}#.*',
- "13:RFXX10REC" => '^(20|29)[A-Fa-f0-9]+',
- "14:Dooya" => '^P16#[A-Fa-f0-9]+',
- "15:SOMFY" => '^Ys[0-9A-F]+',
- "16:SD_WS_Maverick" => '^P47#[A-Fa-f0-9]+',
- "17:SD_UT" => '^u30#.*', ## BELL 201.2 TXA
- "18:FLAMINGO" => '^P13#[A-Fa-f0-9]+', ## Flamingo Smoke
- "19:CUL_WS" => '^K[A-Fa-f0-9]{5,}',
- "20:Revolt" => '^r[A-Fa-f0-9]{22}',
- "21:FS10" => '^P61#[A-F0-9]+',
- "22:Siro" => '^P72#[A-Fa-f0-9]+',
- "23:FHT" => "^81..(04|09|0d)..(0909a001|83098301|c409c401)..",
- "24:FS20" => "^81..(04|0c)..0101a001",
- "X:SIGNALduino_un" => '^[u]\d+#.*',
- );
- my %ProtocolListSIGNALduino = (
- "0" =>
- {
- name => 'weather1', # Logilink, NC, WS, TCM97001 etc.
- comment => 'Logilink, NC, WS, TCM97001 etc',
- id => '0',
- one => [1,-8],
- zero => [1,-4],
- sync => [1,-18],
- clockabs => '500', # not used now
- format => 'twostate', # not used now
- preamble => 's', # prepend to converted message
- postamble => '00', # Append to converted message
- clientmodule => 'CUL_TCM97001', # not used now
- #modulematch => '^s[A-Fa-f0-9]+', # not used now
- length_min => '24',
- length_max => '46',
- paddingbits => '8', # pad up to 8 bits, default is 4
- },
- "1" =>
- {
- name => 'ConradRSL', #
- id => '1',
- one => [2,-1],
- zero => [1,-2],
- sync => [1,-11],
- clockabs => '560', # not used now
- format => 'twostate', # not used now
- preamble => 'P1#', # prepend to converted message
- postamble => '', # Append to converted message
- clientmodule => 'SD_RSL', # not used now
- modulematch => '^P1#[A-Fa-f0-9]{8}', # not used now
- length_min => '20', # 23
- length_max => '40', # 24
- },
- "2" =>
- {
- name => 'AS, Self build arduino sensor',
- comment => 'developModule. SD_AS module is only in github available',
- developId => 'm',
- id => '2',
- one => [1,-2],
- zero => [1,-1],
- sync => [1,-20],
- clockabs => '500', # not used now
- format => 'twostate',
- preamble => 'P2#', # prepend to converted message
- clientmodule => 'SD_AS', # not used now
- modulematch => '^P2#.{7,8}',
- length_min => '32',
- length_max => '34', # Don't know maximal lenth of a valid message
- paddingbits => '8', # pad up to 8 bits, default is 4
-
- },
- "3" =>
- {
- name => 'itv1',
- id => '3',
- one => [3,-1],
- zero => [1,-3],
- #float => [-1,3], # not full supported now later use
- sync => [1,-31],
- clockabs => -1, # -1=auto
- format => 'twostate', # not used now
- preamble => 'i',
- clientmodule => 'IT', # not used now
- modulematch => '^i......', # not used now
- length_min => '24',
- #length_max => '800', # Don't know maximal lenth of a valid message
- },
- "3.1" =>
- {
- name => 'itv1_sync40',
- comment => 'IT remote Control PAR 1000',
- id => '3',
- one => [3,-1],
- zero => [1,-3],
- #float => [-1,3], # not full supported now later use
- sync => [1,-40],
- clockabs => -1, # -1=auto
- format => 'twostate', # not used now
- preamble => 'i',
- clientmodule => 'IT', # not used now
- modulematch => '^i......', # not used now
- length_min => '24',
- #length_max => '800', # Don't know maximal lenth of a valid message
- },
- "4" =>
- {
- name => 'arctech2',
- id => '4',
- #one => [1,-5,1,-1],
- #zero => [1,-1,1,-5],
- one => [1,-5],
- zero => [1,-1],
- #float => [-1,3], # not full supported now, for later use
- sync => [1,-14],
- clockabs => -1, # -1 = auto
- format => 'twostate', # tristate can't be migrated from bin into hex!
- preamble => 'i', # Append to converted message
- postamble => '00', # Append to converted message
- clientmodule => 'IT', # not used now
- modulematch => '^i......', # not used now
- length_min => '32',
- #length_max => '76', # Don't know maximal lenth of a valid message
- },
- "5" => ## Similar protocol as intertechno, but without sync
- {
- name => 'unitec6899',
- id => '5',
- one => [3,-1],
- zero => [1,-3],
- clockabs => 500, # -1 = auto
- format => 'twostate', # tristate can't be migrated from bin into hex!
- preamble => 'p5#', # Append to converted message
- clientmodule => 'IT', # not used now
- modulematch => '^i......', # not used now
- length_min => '24',
- },
-
- "6" => ## Eurochron Protocol
- {
- name => 'weatherID6',
- id => '6',
- one => [1,-10],
- zero => [1,-5],
- sync => [1,-36], # This special device has no sync
- clockabs => 220, # -1 = auto
- format => 'twostate', # tristate can't be migrated from bin into hex!
- preamble => 'u6#', # Append to converted message
- #clientmodule => '', # not used now
- #modulematch => '^u......', # not used now
- length_min => '24',
- },
- "7" => ## weather sensors like EAS800z
- {
- name => 'weatherID7',
- comment => 'EAS800z, FreeTec NC-7344',
- id => '7',
- one => [1,-4],
- zero => [1,-2],
- sync => [1,-8],
- clockabs => 484,
- format => 'twostate',
- preamble => 'P7#', # prepend to converted message
- clientmodule => 'SD_WS07', # not used now
- modulematch => '^P7#.{6}F.{2}', # not used now
- length_min => '35',
- length_max => '40',
- },
- "8" => ## TX3 (ITTX) Protocol
- {
- name => 'TX3 Protocol',
- id => '8',
- one => [1,-2],
- zero => [2,-2],
- #sync => [1,-8], #
- clockabs => 470, #
- format => 'pwm', #
- preamble => 'TX', # prepend to converted message
- clientmodule => 'CUL_TX', # not used now
- modulematch => '^TX......', # not used now
- length_min => '43',
- length_max => '44',
- remove_zero => 1, # Removes leading zeros from output
- },
- "9" => ## Funk Wetterstation CTW600
- {
- name => 'CTW 600',
- comment => 'FunkWS WH1080/WH3080/CTW600',
- id => '9',
- zero => [3,-2],
- one => [1,-2],
- #float => [-1,3], # not full supported now, for later use
- #sync => [1,-8], #
- clockabs => 480, # -1 = auto undef=noclock
- format => 'pwm', # tristate can't be migrated from bin into hex!
- preamble => 'P9#', # prepend to converted message
- clientmodule => 'SD_WS09', # not used now
- #modulematch => '^u9#.....', # not used now
- length_min => '60',
- length_max => '120',
- },
- "10" => ## Oregon Scientific 2
- {
- name => 'OSV2o3',
- id => '10',
- clockrange => [300,520], # min , max
- format => 'manchester', # tristate can't be migrated from bin into hex!
- clientmodule => 'OREGON',
- modulematch => '^(3[8-9A-F]|[4-6][0-9A-F]|7[0-8]).*',
- length_min => '64',
- length_max => '220',
- method => \&SIGNALduino_OSV2, # Call to process this message
- polarity => 'invert',
- },
- "11" => ## Arduino Sensor
- {
- name => 'AS',
- id => '11',
- clockrange => [380,425], # min , max
- format => 'manchester', # tristate can't be migrated from bin into hex!
- preamble => 'P2#', # prepend to converted message
- clientmodule => 'SD_AS', # not used now
- modulematch => '^P2#.{7,8}',
- length_min => '52',
- length_max => '56',
- method => \&SIGNALduino_AS # Call to process this message
- },
- "12" => ## hideki
- {
- name => 'Hideki protocol',
- id => '12',
- clockrange => [420,510], # min, max better for Bresser Sensors, OK for hideki/Hideki/TFA too
- format => 'manchester',
- preamble => 'P12#', # prepend to converted message
- clientmodule => 'hideki', # not used now
- modulematch => '^P12#75.+', # not used now
- length_min => '71',
- length_max => '128',
- method => \&SIGNALduino_Hideki, # Call to process this message
- polarity => 'invert',
-
- },
- "12.1" => ## hideki
- {
- name => 'Hideki protocol not invert',
- comment => 'only for test of the firmware dev-r33_fixmc',
- id => '12',
- clockrange => [420,510], # min, max better for Bresser Sensors, OK for hideki/Hideki/TFA too
- format => 'manchester',
- preamble => 'P12#', # prepend to converted message
- clientmodule => 'hideki', # not used now
- modulematch => '^P12#75.+', # not used now
- length_min => '71',
- length_max => '128',
- method => \&SIGNALduino_Hideki, # Call to process this message
- #polarity => 'invert',
-
- },
- "13" => ## FLAMINGO FA 21
- {
- name => 'FLAMINGO FA21',
- id => '13',
- one => [1,-2],
- zero => [1,-4],
- sync => [1,-20,10,-1],
- clockabs => 800,
- format => 'twostate',
- preamble => 'P13#', # prepend to converted message
- clientmodule => 'FLAMINGO', # not used now
- #modulematch => 'P13#.*', # not used now
- length_min => '24',
- length_max => '26',
- },
- "13.1" => ## FLAMINGO FA20
- {
- name => 'FLAMINGO FA21 b',
- id => '13',
- one => [1,-2],
- zero => [1,-4],
- start => [20,-1],
- clockabs => 800,
- format => 'twostate',
- preamble => 'P13#', # prepend to converted message
- clientmodule => 'FLAMINGO', # not used now
- #modulematch => 'P13#.*', # not used now
- length_min => '24',
- length_max => '24',
- },
-
- "14" => ## Heidemann HX
- {
- name => 'Heidemann HX',
- id => '14',
- one => [1,-2],
- zero => [1,-1],
- #float => [-1,3], # not full supported now, for later use
- sync => [1,-14], #
- clockabs => 350,
- format => 'twostate',
- preamble => 'u14#', # prepend to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '10',
- length_max => '20',
- },
- "15" => ## TCM234759
- {
- name => 'TCM Bell',
- id => '15',
- one => [1,-1],
- zero => [1,-2],
- sync => [1,-45], #
- clockabs => 700,
- format => 'twostate',
- preamble => 'u15#', # prepend to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '10',
- length_max => '20',
- #method => \&SIGNALduino_Cresta # Call to process this message
- },
- "16" => # Rohrmotor24 und andere Funk Rolladen / Markisen Motoren
- {
- name => 'Dooya shutter',
- id => '16',
- one => [2,-1],
- zero => [1,-3],
- start => [17,-5],
- clockabs => 280,
- format => 'twostate',
- preamble => 'P16#', # prepend to converted message
- clientmodule => 'Dooya', # not used now
- #modulematch => '', # not used now
- length_min => '39',
- length_max => '40',
- },
- "17" =>
- {
- name => 'arctech',
- id => '17',
- one => [1,-5,1,-1],
- zero => [1,-1,1,-5],
- #one => [1,-5],
- #zero => [1,-1],
- sync => [1,-10],
- float => [1,-1,1,-1],
- clockabs => -1, # -1 = auto
- format => 'twostate', # tristate can't be migrated from bin into hex!
- preamble => 'i', # Append to converted message
- postamble => '00', # Append to converted message
- clientmodule => 'IT', # not used now
- modulematch => '^i......', # not used now
- length_min => '32',
- #length_max => '76', # Don't know maximal lenth of a valid message
- postDemodulation => \&SIGNALduino_bit2Arctec,
- },
-
- "18" => ## Oregon Scientific v1
- {
- name => 'OSV1',
- id => '18',
- clockrange => [1400,1500], # min , max
- format => 'manchester', # tristate can't be migrated from bin into hex!
- preamble => '',
- clientmodule => 'OREGON',
- modulematch => '^[0-9A-F].*',
- length_min => '31',
- length_max => '32',
- polarity => 'invert', # invert bits
- method => \&SIGNALduino_OSV1 # Call to process this message
- },
- #"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;
- #
- # {
- # name => 'unknown19',
- # id => '19',
- # one => [1,-2],
- # zero => [1,-1],
- # sync => [1,-50,1,-22],
- # clockabs => 395,
- # format => 'twostate',
- # preamble => 'u19#', # prepend to converted message
- # #clientmodule => '', # not used now
- # #modulematch => '', # not used now
- # length_min => '16',
- # length_max => '32',
- # },
- "20" => #Livolo
- {
- name => 'livolo',
- id => '20',
- one => [3],
- zero => [1],
- start => [5],
- clockabs => 110, #can be 90-140
- format => 'twostate',
- preamble => 'u20#', # prepend to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '16',
- filterfunc => 'SIGNALduino_filterSign',
- },
- "21" => #Einhell Garagentor
- {
- name => 'einhell garagedoor',
- id => '21',
- one => [-3,1],
- zero => [-1,3],
- #sync => [-50,1],
- start => [-50,1],
- clockabs => 400, #ca 400us
- format => 'twostate',
- preamble => 'u21#', # prepend to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '32',
- length_max => '32',
- paddingbits => '1', # This will disable padding
- },
- "22" => #TX-EZ6 / Meteo
- {
- name => 'TX-EZ6',
- id => '22',
- one => [1,-8],
- zero => [1,-3],
- sync => [1,16],
- clockabs => 500, #ca 400us
- format => 'twostate',
- preamble => 'u22#', # prepend to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '40',
- #length_max => '', # must be tested
- },
- "23" => # Pearl Sensor
- {
- name => 'perl unknown',
- id => '23',
- one => [1,-6],
- zero => [1,-1],
- sync => [1,-50],
- clockabs => 200, #ca 200us
- format => 'twostate',
- preamble => 'u23#', # prepend to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '36',
- length_max => '44',
- },
- "24" => # visivon
- {
- name => 'visivon remote',
- id => '24',
- one => [3,-2],
- zero => [1,-5],
- #one => [3,-2],
- #zero => [1,-1],
- start => [30,-5],
- clockabs => 150, #ca 150us
- format => 'twostate',
- preamble => 'u24#', # prepend to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '54',
- length_max => '58',
- },
-
- "25" => # LES remote for led lamp
- {
- name => 'les led remote',
- id => '25',
- one => [-2,1],
- zero => [-1,2],
- sync => [-46,1], # this is a end marker, but we use this as a start marker
- clockabs => 350, #ca 350us
- format => 'twostate',
- preamble => 'u25#', # prepend to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '24',
- length_max => '50', # message has only 24 bit, but we get more than one message, calculation has to be corrected
- },
- "26" => # some remote code send by flamingo style remote controls
- {
- name => 'remote26',
- id => '26',
- one => [1,-3],
- zero => [3,-1],
- # sync => [1,-6], # Message is not provided as MS, due to small fact
- start => [1,-6], # Message is not provided as MS, due to small fact
- clockabs => 380, #ca 380
- format => 'twostate',
- preamble => 'u26#', # prepend to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '24',
- length_max => '24', # message has only 24 bit, but we get more than one message, calculation has to be corrected
- },
- "27" => # some remote code, send by flamingo style remote controls
- {
- name => 'remote27',
- id => '27',
- one => [1,-2],
- zero => [2,-1],
- start => [6,-15], # Message is not provided as MS, worakround is start
- clockabs => 480, #ca 480
- format => 'twostate',
- preamble => 'u27#', # prepend to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '24',
- length_max => '24',
- },
- "28" => # some remote code, send by aldi IC Ledspots
- {
- name => 'IC Ledspot',
- id => '28',
- one => [1,-1],
- zero => [1,-2],
- start => [4,-5],
- clockabs => 600, #ca 600
- format => 'twostate',
- preamble => 'u28#', # prepend to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '8',
- length_max => '8',
- },
- "29" => #
- {
- name => 'HT12e remote',
- id => '29',
- one => [-2,1],
- zero => [-1,2],
- #float => [1,-1],
- start => [-38,1], # Message is not provided as MS, worakround is start
- clockabs => 220, #ca 220
- format => 'tristate', # there is a pause puls between words
- preamble => 'u29#', # prepend to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '10',
- length_max => '12', # message has only 10 bit but is paddet to 12
- },
- "30" => # a unitec remote door reed switch
- {
- name => 'unitec47031',
- comment => 'developModule. SD_UT module is only in github available',
- id => '30',
- developId => 'm',
- one => [-1,2],
- zero => [-2,1],
- start => [-33,1], # Message is not provided as MS, worakround is start
- clockabs => 300, # ca 300 us
- format => 'twostate', # there is a pause puls between words
- preamble => 'u30#', # prepend to converted message
- clientmodule => 'SD_UT', # not used now
- modulematch => '^u30', # not used now
- length_min => '12',
- length_max => '12', # message has only 10 bit but is paddet to 12
- },
- "31" => # Pollin Isotronic
- {
- name => 'pollin isotronic',
- id => '31',
- one => [-1,2],
- zero => [-2,1],
- start => [1],
- clockabs => 600,
- format => 'twostate',
- preamble => 'u31#', # prepend to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '20',
- length_max => '20',
- },
- "32" => #FreeTec PE-6946 -> http://www.free-tec.de/Funkklingel-mit-Voic-PE-6946-919.shtml
- {
- name => 'freetec 6946',
- id => '32',
- one => [4,-2],
- zero => [1,-5],
- sync => [1,-49],
- clockabs => 140, #ca 140us
- format => 'twostate',
- preamble => 'u32#', # prepend to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '24',
- length_max => '24',
- },
- "33" => #Thermo-/Hygrosensor S014
- {
- name => 'weather33', #
- id => '33',
- one => [1,-8],
- zero => [1,-4],
- sync => [1,-15],
- clockabs => '500', # not used now
- format => 'twostate', # not used now
- preamble => 'W33#', # prepend to converted message
- postamble => '', # Append to converted message
- clientmodule => 'SD_WS', # not used now
- #modulematch => '', # not used now
- length_min => '42',
- length_max => '44',
- },
- # "34" => # replaced by 37
- # {
- # name => 'unknown34',
- # id => '34',
- # one => [2,-1],
- # zero => [1,-2],
- # start => [3,-3,3,-3,3,-3,3,-3],
- # clockabs => '240',
- # format => 'twostate', # not used now
- # preamble => 'u34#', # prepend to converted message
- # postamble => '', # Append to converted message
- # #clientmodule => '', # not used now
- # #modulematch => '', # not used now
- # length_min => '40',
- # length_max => '40',
- # },
- "35" =>
- {
- name => 'socket35',
- id => '35',
- one => [1,-4],
- zero => [4,-1],
- sync => [1,-19],
- clockabs => '280',
- format => 'twostate', # not used now
- preamble => 'u35#', # prepend to converted message
- postamble => '', # Append to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '28',
- length_max => '32',
- },
- "36" =>
- {
- name => 'socket36',
- id => '36',
- one => [1,-3],
- zero => [1,-1],
- start => [20,-20],
- clockabs => '500',
- format => 'twostate', # not used now
- preamble => 'u36#', # prepend to converted message
- postamble => '', # Append to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '24',
- length_max => '24',
- },
- "37" => ## Bresser 7009994
- # MU;P0=729;P1=-736;P2=483;P3=-251;P4=238;P5=-491;D=010101012323452323454523454545234523234545234523232345454545232345454545452323232345232340;CP=4;
- # MU;P0=-790;P1=-255;P2=474;P4=226;P6=722;P7=-510;D=721060606060474747472121212147472121472147212121214747212147474721214747212147214721212147214060606060474747472121212140;CP=4;R=216;
- # short pulse of 250 us followed by a 500 us gap is a 0 bit
- # long pulse of 500 us followed by a 250 us gap is a 1 bit
- # sync preamble of pulse, gap, 750 us each, repeated 4 times
- {
- name => 'Bresser 7009994',
- id => '37',
- one => [2,-1],
- zero => [1,-2],
- start => [3,-3,3,-3],
- clockabs => '250',
- format => 'twostate', # not used now
- preamble => 'W37#', # prepend to converted message
- clientmodule => 'SD_WS',
- length_min => '40',
- length_max => '41',
- },
- "38" =>
- {
- name => 'weather38',
- id => '38',
- one => [1,-10],
- zero => [1,-5],
- sync => [1,-25],
- clockabs => '360', # not used now
- format => 'twostate', # not used now
- preamble => 's', # prepend to converted message
- postamble => '00', # Append to converted message
- clientmodule => 'CUL_TCM97001', # not used now
- #modulematch => '^s[A-Fa-f0-9]+', # not used now
- length_min => '32',
- length_max => '32',
- paddingbits => '8',
- },
- "39" => ## X10 Protocol
- {
- name => 'X10 Protocol',
- id => '39',
- one => [1,-3],
- zero => [1,-1],
- start => [17,-7],
- clockabs => 560,
- format => 'twostate',
- preamble => '', # prepend to converted message
- clientmodule => 'RFXX10REC', # not used now
- #modulematch => '^TX......', # not used now
- length_min => '32',
- length_max => '44',
- paddingbits => '8',
- postDemodulation => \&SIGNALduino_lengtnPrefix,
- filterfunc => 'SIGNALduino_compPattern',
-
-
- },
- "40" => ## Romotec
- {
- name => 'romotec',
- id => '40',
- one => [3,-2],
- zero => [1,-3],
- start => [1,-2],
- clockabs => 250,
- preamble => 'u40#', # prepend to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '10',
- length_min => '12',
-
- },
- "41" => ## Elro (Smartwares) Doorbell DB200
- {
- name => 'elro doorbell',
- comment => 'Elro (Smartwares) Doorbell DB200',
- id => '41',
- zero => [1,-3],
- one => [3,-1],
- sync => [1,-15],
- clockabs => 450,
- preamble => 'u41#', # prepend to converted message
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '20',
- },
- #"42" => ## MKT Multi Kon Trade // Sollte eigentlich als MS ITv1 erkannt werden
- # {
- # name => 'MKT motionsensor',
- # id => '42',
- # zero => [1,-3],
- # one => [3,-1],
- # sync => [-28],
- # clockabs => 550,
- # preamble => 'u42#', # prepend to converted message
- # #clientmodule => '', # not used now
- # #modulematch => '',
- # length_min => '24',
- # },
- "43" => ## Somfy RTS
- {
- name => 'Somfy RTS',
- id => '43',
- clockrange => [610,680], # min , max
- format => 'manchester',
- preamble => 'Ys',
- clientmodule => 'SOMFY', # not used now
- modulematch => '^Ys[0-9A-F]{14}',
- length_min => '56',
- length_max => '57',
- method => \&SIGNALduino_SomfyRTS, # Call to process this message
- msgIntro => 'SR;P0=-2560;P1=2560;P3=-640;D=10101010101010113;',
- #msgOutro => 'SR;P0=-30415;D=0;',
- frequency => '10AB85550A',
- },
- "44" => ## Bresser Temeo Trend
- {
- name => 'BresserTemeo',
- id => '44',
- clockabs => 500,
- zero => [4,-4],
- one => [4,-8],
- start => [8,-8],
- preamble => 'W44#',
- clientmodule => 'SD_WS',
- modulematch => '^W44#[A-F0-9]{18}',
- length_min => '64',
- length_max => '72',
- },
- "44.1" => ## Bresser Temeo Trend
- {
- name => 'BresserTemeo',
- id => '44',
- clockabs => 500,
- zero => [4,-4],
- one => [4,-8],
- start => [8,-12],
- preamble => 'W44x#',
- clientmodule => 'SD_WS',
- modulematch => '^W44x#[A-F0-9]{18}',
- length_min => '64',
- length_max => '72',
- },
- "45" => # Revolt
- # MU;P0=-8320;P1=9972;P2=-376;P3=117;P4=-251;P5=232;D=012345434345434345454545434345454545454543454343434343434343434343434543434345434343434545434345434343434343454343454545454345434343454345434343434343434345454543434343434345434345454543454343434543454345434545;CP=3;R=2
- {
- name => 'Revolt',
- id => '45',
- one => [2,-2],
- zero => [1,-2],
- start => [83,-3],
- clockabs => 120,
- preamble => 'r', # prepend to converted message
- clientmodule => 'Revolt',
- modulematch => '^r[A-Fa-f0-9]{22}',
- length_min => '84',
- length_max => '120',
- postDemodulation => sub { my ($name, @bit_msg) = @_; my @new_bitmsg = splice @bit_msg, 0,88; return 1,@new_bitmsg; },
- },
- "46" =>
- {
- name => 'EKX1BE',
- id => '46',
- one => [1,-8],
- zero => [8,-1],
- clockabs => 250, # -1=auto
- format => 'twostate', # not used now
- preamble => 'u46#',
- #clientmodule => '', # not used now
- #modulematch => '', # not used now
- length_min => '16',
- length_max => '18',
-
- },
- "47" => ## maverick
- {
- name => 'Maverick protocol',
- id => '47',
- clockrange => [220,260],
- format => 'manchester',
- preamble => 'P47#', # prepend to converted message
- clientmodule => 'SD_WS_Maverick', # not used now
- modulematch => '^P47#.*', # not used now
- length_min => '100',
- length_max => '108',
- method => \&SIGNALduino_Maverick # Call to process this message
- },
- "48" => ## Joker Dostmann TFA
- {
- name => 'TFA Dostmann',
- id => '48',
- clockabs => 250, # In real it is 500 but this leads to unprceise demodulation
- one => [-4,6],
- zero => [-4,2],
- start => [-6,2],
- format => 'twostate',
- preamble => 'U48#', # prepend to converted message
- #clientmodule => '', # not used now
- modulematch => '^U48#.*', # not used now
- length_min => '47',
- length_max => '48',
- },
- "49" => ## quigg / Aldi gt_9000
- {
- name => 'quigg_gt9000',
- id => '49',
- clockabs => 400,
- one => [2,-1],
- zero => [1,-3],
- start => [-15,2,-1],
- format => 'twostate',
- preamble => 'U49#', # prepend to converted message
- #clientmodule => '', # not used now
- modulematch => '^U49#.*', # not used now
- length_min => '22',
- length_max => '28',
- },
- "50" => ## Opus XT300
- {
- name => 'optus_XT300',
- id => '50',
- clockabs => 500,
- zero => [3,-2],
- one => [1,-2],
- # start => [1,-25], # Wenn das startsignal empfangen wird, fehlt das 1 bit
- format => 'twostate',
- preamble => 'W50#', # prepend to converted message
- clientmodule => 'SD_WS', # not used now
- modulematch => '^W50#.*', # not used now
- length_min => '47',
- length_max => '48',
- },
- "51" =>
- { # MS;P0=-16046;P1=552;P2=-1039;P3=983;P5=-7907;P6=-1841;P7=-4129;D=15161716171616161717171716161616161617161717171717171617171617161716161616161616171032323232;CP=1;SP=5;O;
- name => 'weather51', # Logilink, NC, WS, TCM97001 etc.
- comment => 'IAN 275901 Wetterstation Lidl',
- id => '51',
- one => [1,-8],
- zero => [1,-4],
- sync => [1,-13],
- clockabs => '560', # not used now
- format => 'twostate', # not used now
- preamble => 'W51#', # prepend to converted message
- postamble => '', # Append to converted message
- clientmodule => 'SD_WS',
- modulematch => '^W51#.*',
- length_min => '40',
- length_max => '45',
- },
- "52" => ## Oregon PIR Protocol
- {
- name => 'OS_PIR',
- id => '52',
- clockrange => [470,640], # min , max
- format => 'manchester', # tristate can't be migrated from bin into hex!
- clientmodule => 'OREGON',
- modulematch => '^u52#F{3}|0{3}.*',
- preamble => 'u52#',
- length_min => '30',
- length_max => '30',
- method => \&SIGNALduino_OSPIR, # Call to process this message
- polarity => 'invert',
- },
-
- "55" => ##quigg gt1000
- {
- name => 'quigg_gt1000',
- id => '55',
- clockabs => 300,
- zero => [1,-4],
- one => [4,-2],
- sync => [1,-8],
- format => 'twostate',
- preamble => 'i', # prepend to converted message
- clientmodule => 'IT', # not used now
- modulematch => '^i.*', # not used now
- length_min => '24',
- length_max => '24',
- },
- "56" => ## Celexon
- {
- name => 'Celexon',
- id => '56',
- clockabs => 200,
- zero => [1,-3],
- one => [3,-1],
- start => [25,-3],
- format => 'twostate',
- preamble => 'u56#', # prepend to converted message
- #clientmodule => '' , # not used now
- modulematch => '', # not used now
- length_min => '56',
- length_max => '68',
- },
- "57" => ## m-e doorbell
- {
- name => 'm-e',
- id => '57',
- clockrange => [300,360], # min , max
- format => 'manchester', # tristate can't be migrated from bin into hex!
- clientmodule => '',
- modulematch => '^u57*',
- preamble => 'u57#',
- length_min => '21',
- length_max => '24',
- method => \&SIGNALduino_MCRAW, # Call to process this message
- polarity => 'invert',
- },
- "58" => ## tfa 30.3208.0
- {
- name => 'tfa 30.3208.0 ',
- id => '58',
- clockrange => [460,520], # min , max
- format => 'manchester', # tristate can't be migrated from bin into hex!
- clientmodule => '',
- modulematch => '^W58*',
- preamble => 'W58#',
- length_min => '54',
- length_max => '136',
- method => \&SIGNALduino_MCTFA, # Call to process this message
- polarity => 'invert',
- },
- "59" => ## AK-HD-4 remote
- {
- name => 'AK-HD-4',
- id => '59',
- clockabs => 230,
- zero => [-4,1],
- one => [-1,4],
- start => [-1,37],
- format => 'twostate', # tristate can't be migrated from bin into hex!
- preamble => 'u59#', # Append to converted message
- postamble => '', # Append to converted message
- #clientmodule => '', # not used now
- modulematch => '', # not used now
- length_min => '24',
- length_max => '24',
- },
- "60" => ## ELV, LA CROSSE (WS2000/WS7000)
- {
- # 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,
- # ASH2200, S300IA, S2001I, S2000ID, S2001ID, S2500H
- # not tested: AS3, S2000W, S2000R, WS7000-15, WS7000-16, WS2500-19, S300TH, S555TH
- # das letzte Bit 1 und 1 x 0 Preambel fehlt meistens
- # ___ _
- # | |_ | |___
- # Bit 0 Bit 1
- # kurz 366 µSek / lang 854 µSek / gesamt 1220 µSek - Sollzeiten
- name => 'WS2000',
- id => '60',
- one => [3,-7],
- zero => [7,-3],
- clockabs => 122,
- preamble => 'K', # prepend to converted message
- postamble => '', # Append to converted message
- clientmodule => 'CUL_WS',
- length_min => '44', # eigentlich 46
- length_max => '82', # eigentlich 81
- postDemodulation => \&SIGNALduino_postDemo_WS2000,
- },
- "61" => ## ELV FS10
- # tested transmitter: FS10-S8, FS10-S4, FS10-ZE
- # tested receiver: FS10-ST, FS10-MS, WS3000-TV, PC-Wettersensor-Empfaenger
- # das letzte Bit 1 und 1 x 0 Preambel fehlt immer
- {
- name => 'FS10',
- id => '61',
- one => [1,-2],
- zero => [1,-1],
- clockabs => 400,
- format => 'twostate',
- preamble => 'P61#', # prepend to converted message
- postamble => '', # Append to converted message
- clientmodule => 'FS10',
- #modulematch => '',
- length_min => '38', # eigentlich 41 oder 46 (Pruefsumme nicht bei allen)
- length_max => '48', # eigentlich 46
-
- },
- "62" => ## Clarus_Switch
- { #MU;P0=-5893;P4=-634;P5=498;P6=-257;P7=116;D=45656567474747474745656707456747474747456745674567456565674747474747456567074567474747474567456745674565656747474747474565670745674747474745674567456745656567474747474745656707456747474747456745674567456565674747474747456567074567474747474567456745674567;CP=7;O;
- name => 'Clarus_Switch',
- id => '62',
- one => [3,-1],
- zero => [1,-3],
- start => [1,-35], # ca 30-40
- clockabs => 189,
- preamble => 'i', # prepend to converted message
- clientmodule => 'IT',
- #modulematch => '',
- length_min => '24',
- length_max => '24',
- },
- "63" => ## Warema MU
- { #MU;P0=-2988;P1=1762;P2=-1781;P3=-902;P4=871;P5=6762;P6=5012;D=0121342434343434352434313434243521342134343436;
- name => 'Warema',
- comment => 'developId, is still experimental',
- id => '63',
- developId => 'y',
- one => [1],
- zero => [0],
- clockabs => 800,
- syncabs => '6700',# Special field for filterMC function
- preamble => 'u63', # prepend to converted message
- #clientmodule => '',
- #modulematch => '',
- length_min => '24',
- filterfunc => 'SIGNALduino_filterMC',
- },
- "64" => ## WH2 #############################################################################
- {
- # MU;P0=-32001;P1=457;P2=-1064;P3=1438;D=0123232323212121232123232321212121212121212323212121232321;CP=1;R=63;
- # MU;P0=-32001;P1=473;P2=-1058;P3=1454;D=0123232323212121232123232121212121212121212121232321212321;CP=1;R=51;
- #MU;P0=134;P1=-113;P3=412;P4=-1062;P5=1379;D=01010101013434343434343454345454345454545454345454545454343434545434345454345454545454543454543454345454545434545454345;CP=3;
- name => 'WH2',
- id => '64',
- one => [1,-2],
- zero => [3,-2],
- clockabs => 490,
- clientmodule => 'SD_WS',
- modulematch => '^W64*',
- preamble => 'W64#', # prepend to converted message
- postamble => '', # Append to converted message
- #clientmodule => '',
- length_min => '48',
- length_max => '54',
- },
- "65" => ## Homeeasy
- {
- name => 'Homeeasy',
- id => '65',
- one => [1,-5],
- zero => [1,-1],
- start => [1,-40],
- clockabs => 250,
- format => 'twostate', # not used now
- preamble => 'U65#',
- length_min => '50',
- #msgOutro => 'SR;P0=275;P1=-7150;D=01;',
- postDemodulation => \&SIGNALduino_HE,
- },
- "66" => ## TX2 Protocol (Remote Temp Transmitter & Remote Thermo Model 7035)
- # MU;P0=13312;P1=-2785;P2=4985;P3=1124;P4=-6442;P5=3181;P6=-31980;D=0121345434545454545434545454543454545434343454543434545434545454545454343434545434343434545621213454345454545454345454545434545454343434545434345454345454545454543434345454343434345456212134543454545454543454545454345454543434345454343454543454545454545;CP=3;R=73;O;
- {
- name => 'WS7035',
- id => '66',
- one => [10,-52],
- zero => [27,-52],
- start => [-21,42,-21],
- clockabs => 122,
- format => 'pwm', # not used now
- preamble => 'TX',
- clientmodule => 'CUL_TX',
- modulematch => '^TX......',
- length_min => '43',
- length_max => '44',
- postDemodulation => \&SIGNALduino_postDemo_WS7035,
- },
- "67" => ## TX2 Protocol (Remote Datalink & Remote Thermo Model 7053)
- # MU;P0=3381;P1=-672;P2=-4628;P3=1142;P4=-30768;D=0102320232020202020232020232020202320232323202323202020202020202020401023202320202020202320202320202023202323232023232020202020202020200;CP=0;R=45;
- # MU;P0=1148;P1=3421;P6=-664;P7=-4631;D=16170717071717171717071717071717171717070707170717171717070717171710;CP=1;R=29;
- # MU;P0=3389;P3=2560;P4=-720;P5=1149;P7=-4616;D=345407570757070707070757070757070707070757570707075707070707570757575;CP=5;R=253;
- # __ ____
- # ________| | ________| |
- # Bit 1 Bit 0
- # 4630 1220 4630 3420 µSek - mit Oszi gemessene Zeiten
- {
- name => 'WS7053',
- id => '67',
- one => [-38,10],
- zero => [-38,28],
- clockabs => 122,
- preamble => 'TX', # prepend to converted message
- clientmodule => 'CUL_TX',
- modulematch => '^TX......',
- length_min => '32',
- length_max => '34',
- postDemodulation => \&SIGNALduino_postDemo_WS7053,
- },
- "68" => ## PFR-130 ###########################################################################
- {
- # MS;P0=-3890;P1=386;P2=-2191;P3=-8184;D=1312121212121012121212121012121212101012101010121012121210121210101210101012;CP=1;SP=3;R=20;O;
- # MS;P0=-2189;P1=371;P2=-3901;P3=-8158;D=1310101010101210101010101210101010121210121212101210101012101012121012121210;CP=1;SP=3;R=20;O;
- name => 'PFR-130',
- id => '68',
- one => [1,-10],
- zero => [1,-5],
- sync => [1,-21],
- clockabs => 380, # not used now
- preamble => 's', # prepend to converted message
- postamble => '00', # Append to converted message
- clientmodule => 'CUL_TCM97001', # not used now
- length_min => '24',
- length_max => '42',
- paddingbits => '8', # pad up to 8 bits, default is 4
- },
- "69" => ## Hoermann
- # MU;P0=-508;P1=1029;P2=503;P3=-1023;P4=12388;D=01010232323232310104010101010101010102323231010232310231023232323231023101023101010231010101010232323232310104010101010101010102323231010232310231023232323231023101023101010231010101010232323232310104010101010101010102323231010232310231023232323231023101;CP=2;R=37;O;
- {
- name => 'Hoermann',
- id => '69',
- zero => [2,-1],
- one => [1,-2],
- start => [24,-1],
- clockabs => 510,
- format => 'twostate', # not used now
- #clientmodule => '',
- #modulematch => '^U69*',
- preamble => 'U69#',
- length_min => '40',
- #length_max => '90',
- postDemodulation => \&SIGNALduino_postDemo_Hoermann, # Call to process this message
- },
- "70" => ## FHT80TF (Funk-Tuer-Fenster-Melder FHT 80TF und FHT 80TF-2)
- # closed MU;P0=-24396;P1=417;P2=-376;P3=610;P4=-582;D=012121212121212121212121234123434121234341212343434121234123434343412343434121234341212121212341212341234341234123434;CP=1;R=35;
- # open MU;P0=-21652;P1=429;P2=-367;P4=634;P5=-555;D=012121212121212121212121245124545121245451212454545121245124545454512454545121245451212121212124512451245451245121212;CP=1;R=38;
- {
- name => 'FHT80TF',
- comment => 'Door/Window switch (868Mhz)',
- id => '70',
- one => [1.5,-1.5], # 600
- zero => [1,-1], # 400
- clockabs => 400,
- format => 'twostate', # not used now
- clientmodule => 'CUL_FHTTK',
- preamble => 'T',
- length_min => '50',
- length_max => '58',
- postDemodulation => \&SIGNALduino_postDemo_FHT80TF,
- },
- "71" => ## PV-8644 infactory Poolthermometer
- # MU;P0=1735;P1=-1160;P2=591;P3=-876;D=0123012323010101230101232301230123010101010123012301012323232323232301232323232323232323012301012;CP=2;R=97;
- {
- name => 'PV-8644',
- comment => 'infactory Poolthermometer',
- id => '71',
- clockabs => 580,
- zero => [3,-2],
- one => [1,-1.5],
- format => 'twostate',
- preamble => 'W71#', # prepend to converted message
- clientmodule => 'SD_WS',
- #modulematch => '^W71#.*'
- length_min => '48',
- length_max => '48',
- },
- # MU;P0=-760;P1=334;P2=693;P3=-399;P4=-8942;P5=4796;P6=-1540;D=01010102310232310101010102310232323101010102310101010101023102323102323102323102310101010102310232323101010102310101010101023102310231023102456102310232310232310231010101010231023232310101010231010101010102310231023102310245610231023231023231023101010101;CP=1;R=45;O;
- # MU;P0=-8848;P1=4804;P2=-1512;P3=336;P4=-757;P5=695;P6=-402;D=0123456345656345656345634343434345634565656343434345634343434343456345634563456345;CP=3;R=49;
-
- "72" => # Siro blinds MU @Dr. Smag
- {
- name => 'Siro shutter',
- comment => 'developModule. Siro is not in github or SVN available',
- id => '72',
- developId => 'm',
- dispatchequals => 'true',
- one => [2,-1.2], # 680, -400
- zero => [1,-2.2], # 340, -750
- start => [14,-4.4], # 4800,-1520
- clockabs => 340,
- format => 'twostate',
- preamble => 'P72#', # prepend to converted message
- clientmodule => 'Siro',
- #modulematch => '',
- length_min => '39',
- length_max => '40',
- msgOutro => 'SR;P0=-8500;D=0;',
- },
-
- # MS;P0=4803;P1=-1522;P2=333;P3=-769;P4=699;P5=-393;P6=-9190;D=2601234523454523454523452323232323452345454523232323452323232323234523232345454545;CP=2;SP=6;R=61;
- "72.1" => # Siro blinds MS @Dr. Smag
- {
- name => 'Siro shutter',
- comment => 'developModule. Siro is not in github or SVN available',
- id => '72',
- developId => 'm',
- dispatchequals => 'true',
- one => [2,-1.2], # 680, -400
- zero => [1,-2.2], # 340, -750
- sync => [14,-4.4], # 4800,-1520
- clockabs => 340,
- format => 'twostate',
- preamble => 'P72#', # prepend to converted message
- clientmodule => 'Siro',
- #modulematch => '',
- length_min => '39',
- length_max => '40',
- #msgOutro => 'SR;P0=-8500;D=0;',
- },
- "73" => ## FHT80 - Raumthermostat (868Mhz), @HomeAutoUser
- {
- name => 'FHT80',
- comment => 'Roomthermostat (868Mhz only receive)',
- id => '73',
- developId => 'y',
- one => [1.5,-1.5], # 600
- zero => [1,-1], # 400
- clockabs => 400,
- format => 'twostate', # not used now
- clientmodule => 'FHT',
- preamble => '810c04xx0909a001',
- length_min => '59',
- length_max => '67',
- postDemodulation => \&SIGNALduino_postDemo_FHT80,
- },
- "74" => ## FS20 - 'Remote Control (868Mhz), @HomeAutoUser
- {
- name => 'FS20',
- comment => 'Remote Control (868Mhz only receive)',
- id => '74',
- developId => 'y',
- one => [1.5,-1.5], # 600
- zero => [1,-1], # 400
- clockabs => 400,
- format => 'twostate', # not used now
- clientmodule => 'FS20',
- preamble => '810b04f70101a001',
- length_min => '50',
- length_max => '67',
- postDemodulation => \&SIGNALduino_postDemo_FS20,
- },
- "75" => ## ConradRSL2 @litronics https://github.com/RFD-FHEM/SIGNALDuino/issues/69
- # MU;P0=-1365;P1=477;P2=1145;P3=-734;P4=-6332;D=01023202310102323102423102323102323101023232323101010232323231023102323102310102323102423102323102323101023232323101010232323231023102323102310102323102;CP=1;R=12;
- {
- name => 'ConradRSL2',
- id => '75',
- one => [3,-1],
- zero => [1,-3],
- clockabs => 500,
- format => 'twostate',
- clientmodule => 'SD_RSL',
- preamble => 'P1#',
- modulematch => '^P1#[A-Fa-f0-9]{8}',
- length_min => '32',
- length_max => '40',
- },
- "76" => ## Kabellose LED-Weihnachtskerzen XM21-0
- {
- name => 'xm21',
- comment => 'reserviert, LED Lichtrekette on',
- id => '76',
- developId => 'p',
- one => [1.2,-2], # 120,-200
- zero => [], # existiert nicht
- start => [4.5,-2], # 450,-200 Starsequenz
- clockabs => 100,
- format => 'twostate', # not used now
- clientmodule => '',
- preamble => 'P76',
- length_min => 64,
- length_max => 64,
- },
- "76.1" => ## Kabellose LED-Weihnachtskerzen XM21-0
- {
- name => 'xm21',
- comment => 'reserviert, LED Lichtrekette off',
- id => '76.1',
- developId => 'p',
- one => [1.2,-2], # 120,-200
- zero => [], # existiert nicht
- start => [4.5,-2], # 450,-200 Starsequenz
- clockabs => 100,
- format => 'twostate', # not used now
- clientmodule => '',
- preamble => 'P76',
- length_min => 58,
- length_max => 58,
- },
- );
- sub
- SIGNALduino_Initialize($)
- {
- my ($hash) = @_;
- require "$attr{global}{modpath}/FHEM/DevIo.pm";
- # Provider
- $hash->{ReadFn} = "SIGNALduino_Read";
- $hash->{WriteFn} = "SIGNALduino_Write";
- $hash->{ReadyFn} = "SIGNALduino_Ready";
- # Normal devices
- $hash->{DefFn} = "SIGNALduino_Define";
- $hash->{FingerprintFn} = "SIGNALduino_FingerprintFn";
- $hash->{UndefFn} = "SIGNALduino_Undef";
- $hash->{GetFn} = "SIGNALduino_Get";
- $hash->{SetFn} = "SIGNALduino_Set";
- $hash->{AttrFn} = "SIGNALduino_Attr";
- $hash->{AttrList} =
- "Clients MatchList do_not_notify:1,0 dummy:1,0"
- ." hexFile"
- ." initCommands"
- ." flashCommand"
- ." hardware:nano328,uno,promini328,nanoCC1101"
- ." debug:0,1"
- ." longids"
- ." minsecs"
- ." whitelist_IDs"
- ." blacklist_IDs"
- ." WS09_CRCAUS:0,1,2"
- ." addvaltrigger"
- ." rawmsgEvent:1,0"
- ." cc1101_frequency"
- ." doubleMsgCheck_IDs"
- ." suppressDeviceRawmsg:1,0"
- ." development"
- ." noMsgVerbose:0,1,2,3,4,5"
- ." $readingFnAttributes";
- $hash->{ShutdownFn} = "SIGNALduino_Shutdown";
-
- $hash->{msIdList} = ();
- $hash->{muIdList} = ();
- $hash->{mcIdList} = ();
-
- }
- sub
- SIGNALduino_FingerprintFn($$)
- {
- my ($name, $msg) = @_;
- # Store only the "relevant" part, as the Signalduino won't compute the checksum
- #$msg = substr($msg, 8) if($msg =~ m/^81/ && length($msg) > 8);
- return ($name, $msg);
- }
- #####################################
- sub
- SIGNALduino_Define($$)
- {
- my ($hash, $def) = @_;
- my @a = split("[ \t][ \t]*", $def);
- if(@a != 3) {
- my $msg = "wrong syntax: define <name> SIGNALduino {none | devicename[\@baudrate] | devicename\@directio | hostname:port}";
- Log3 undef, 2, $msg;
- return $msg;
- }
-
- DevIo_CloseDev($hash);
- my $name = $a[0];
-
- if (!exists &round)
- {
- Log3 $name, 1, "$name: Signalduino can't be activated (sub round not found). Please update Fhem via update command";
- return undef;
- }
-
- my $dev = $a[2];
- #Debug "dev: $dev" if ($debug);
- #my $hardware=AttrVal($name,"hardware","nano328");
- #Debug "hardware: $hardware" if ($debug);
-
-
- if($dev eq "none") {
- Log3 $name, 1, "$name: device is none, commands will be echoed only";
- $attr{$name}{dummy} = 1;
- #return undef;
- }
-
- if ($dev ne "none" && $dev =~ m/[a-zA-Z]/ && $dev !~ m/\@/) { # bei einer IP wird kein \@57600 angehaengt
- $dev .= "\@57600";
- }
-
- #$hash->{CMDS} = "";
- $hash->{Clients} = $clientsSIGNALduino;
- $hash->{MatchList} = \%matchListSIGNALduino;
-
- #if( !defined( $attr{$name}{hardware} ) ) {
- # $attr{$name}{hardware} = "nano328";
- #}
- if( !defined( $attr{$name}{flashCommand} ) ) {
- # $attr{$name}{flashCommand} = "avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]"
- $attr{$name}{flashCommand} = "avrdude -c arduino -b [BAUDRATE] -P [PORT] -p atmega328p -vv -U flash:w:[HEXFILE] 2>[LOGFILE]";
-
- }
- $hash->{DeviceName} = $dev;
-
- my $ret=undef;
-
- InternalTimer(gettimeofday(), 'SIGNALduino_IdList',"sduino_IdList:$name",0); # verzoegern bis alle Attribute eingelesen sind
-
- if($dev ne "none") {
- $ret = DevIo_OpenDev($hash, 0, "SIGNALduino_DoInit", 'SIGNALduino_Connect');
- } else {
- $hash->{DevState} = 'initialized';
- readingsSingleUpdate($hash, "state", "opened", 1);
- }
-
- $hash->{DMSG}="nothing";
- $hash->{LASTDMSG} = "nothing";
- $hash->{TIME}=time();
-
-
- Log3 $name, 3, "$name: Firmwareversion: ".$hash->{READINGS}{version}{VAL} if ($hash->{READINGS}{version}{VAL});
- return $ret;
- }
- ###############################
- sub SIGNALduino_Connect($$)
- {
- my ($hash, $err) = @_;
- # damit wird die err-msg nur einmal ausgegeben
- if (!defined($hash->{disConnFlag}) && $err) {
- Log3($hash, 3, "SIGNALduino $hash->{NAME}: ${err}");
- $hash->{disConnFlag} = 1;
- }
- }
- #####################################
- sub
- SIGNALduino_Undef($$)
- {
- my ($hash, $arg) = @_;
- my $name = $hash->{NAME};
-
-
-
- foreach my $d (sort keys %defs) {
- if(defined($defs{$d}) &&
- defined($defs{$d}{IODev}) &&
- $defs{$d}{IODev} == $hash)
- {
- my $lev = ($reread_active ? 4 : 2);
- Log3 $name, $lev, "$name: deleting port for $d";
- delete $defs{$d}{IODev};
- }
- }
- SIGNALduino_Shutdown($hash);
-
- DevIo_CloseDev($hash);
- RemoveInternalTimer($hash);
- return undef;
- }
- #####################################
- sub
- SIGNALduino_Shutdown($)
- {
- my ($hash) = @_;
- #DevIo_SimpleWrite($hash, "XQ\n",2);
- SIGNALduino_SimpleWrite($hash, "XQ"); # Switch reception off, it may hang up the SIGNALduino
- return undef;
- }
- #####################################
- #$hash,$name,"sendmsg","P17;R6#".substr($arg,2)
- sub
- SIGNALduino_Set($@)
- {
- my ($hash, @a) = @_;
-
- return "\"set SIGNALduino\" needs at least one parameter" if(@a < 2);
- #Log3 $hash, 3, "SIGNALduino_Set called with params @a";
- my $hasCC1101 = 0;
- my $CC1101Frequency;
- if ($hash->{version} && $hash->{version} =~ m/cc1101/) {
- $hasCC1101 = 1;
- if (!defined($hash->{cc1101_frequency})) {
- $CC1101Frequency = "433";
- } else {
- $CC1101Frequency = $hash->{cc1101_frequency};
- }
- }
- if (!defined($sets{$a[1]})) {
- my $arguments = ' ';
- foreach my $arg (sort keys %sets) {
- next if ($arg =~ m/cc1101/ && $hasCC1101 == 0);
- if ($arg =~ m/patable/) {
- next if (substr($arg, -3) ne $CC1101Frequency);
- }
- $arguments.= $arg . ($sets{$arg} ? (':' . $sets{$arg}) : '') . ' ';
- }
- #Log3 $hash, 3, "set arg = $arguments";
- return "Unknown argument $a[1], choose one of " . $arguments;
- }
- my $name = shift @a;
- my $cmd = shift @a;
- my $arg = join(" ", @a);
-
- if ($cmd =~ m/cc1101/ && $hasCC1101 == 0) {
- return "This command is only available with a cc1101 receiver";
- }
-
- 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');
- if ($cmd =~ m/^cc1101_/) {
- $cmd = substr($cmd,7);
- }
-
- if($cmd eq "raw") {
- Log3 $name, 4, "set $name $cmd $arg";
- #SIGNALduino_SimpleWrite($hash, $arg);
- SIGNALduino_AddSendQueue($hash,$arg);
- } elsif( $cmd eq "flash" ) {
- my @args = split(' ', $arg);
- my $log = "";
- my $hexFile = "";
- my @deviceName = split('@', $hash->{DeviceName});
- my $port = $deviceName[0];
- my $hardware=AttrVal($name,"hardware","nano328");
- my $baudrate=$hardware eq "uno" ? 115200 : 57600;
- my $defaultHexFile = "./FHEM/firmware/$hash->{TYPE}_$hardware.hex";
- my $logFile = AttrVal("global", "logdir", "./log/") . "$hash->{TYPE}-Flash.log";
- if(!$arg || $args[0] !~ m/^(\w|\/|.)+$/) {
- $hexFile = AttrVal($name, "hexFile", "");
- if ($hexFile eq "") {
- $hexFile = $defaultHexFile;
- }
- }
- elsif ($args[0] =~ m/^https?:\/\// ) {
- my $http_param = {
- url => $args[0],
- timeout => 5,
- hash => $hash, # Muss gesetzt werden, damit die Callback funktion wieder $hash hat
- method => "GET", # Lesen von Inhalten
- callback => \&SIGNALduino_ParseHttpResponse, # Diese Funktion soll das Ergebnis dieser HTTP Anfrage bearbeiten
- command => 'flash',
- };
-
- HttpUtils_NonblockingGet($http_param);
- return;
- } else {
- $hexFile = $args[0];
- }
- Log3 $name, 3, "$name: filename $hexFile provided, trying to flash";
-
- return "Usage: set $name flash [filename]\n\nor use the hexFile attribute" if($hexFile !~ m/^(\w|\/|.)+$/);
- $log .= "flashing Arduino $name\n";
- $log .= "hex file: $hexFile\n";
- $log .= "port: $port\n";
- $log .= "log file: $logFile\n";
- my $flashCommand = AttrVal($name, "flashCommand", "");
- if($flashCommand ne "") {
- if (-e $logFile) {
- unlink $logFile;
- }
- DevIo_CloseDev($hash);
- $hash->{STATE} = "disconnected";
- $log .= "$name closed\n";
- my $avrdude = $flashCommand;
- $avrdude =~ s/\Q[PORT]\E/$port/g;
- $avrdude =~ s/\Q[BAUDRATE]\E/$baudrate/g;
- $avrdude =~ s/\Q[HEXFILE]\E/$hexFile/g;
- $avrdude =~ s/\Q[LOGFILE]\E/$logFile/g;
- $log .= "command: $avrdude\n\n";
- `$avrdude`;
- local $/=undef;
- if (-e $logFile) {
- open FILE, $logFile;
- my $logText = <FILE>;
- close FILE;
- $log .= "--- AVRDUDE ---------------------------------------------------------------------------------\n";
- $log .= $logText;
- $log .= "--- AVRDUDE ---------------------------------------------------------------------------------\n\n";
- }
- else {
- $log .= "WARNING: avrdude created no log file\n\n";
- }
- }
- else {
- $log .= "\n\nNo flashCommand found. Please define this attribute.\n\n";
- }
- DevIo_OpenDev($hash, 0, "SIGNALduino_DoInit", 'SIGNALduino_Connect');
- $log .= "$name opened\n";
- return $log;
- } elsif ($cmd =~ m/reset/i) {
- delete($hash->{initResetFlag}) if defined($hash->{initResetFlag});
- return SIGNALduino_ResetDevice($hash);
- } elsif( $cmd eq "close" ) {
- $hash->{DevState} = 'closed';
- return SIGNALduino_CloseDevice($hash);
- } elsif( $cmd eq "disableMessagetype" ) {
- my $argm = 'CD' . substr($arg,-1,1);
- #SIGNALduino_SimpleWrite($hash, $argm);
- SIGNALduino_AddSendQueue($hash,$argm);
- Log3 $name, 4, "set $name $cmd $arg $argm";;
- } elsif( $cmd eq "enableMessagetype" ) {
- my $argm = 'CE' . substr($arg,-1,1);
- #SIGNALduino_SimpleWrite($hash, $argm);
- SIGNALduino_AddSendQueue($hash,$argm);
- Log3 $name, 4, "set $name $cmd $arg $argm";
- } elsif( $cmd eq "freq" ) {
- if ($arg eq "") {
- $arg = AttrVal($name,"cc1101_frequency", 433.92);
- }
- my $f = $arg/26*65536;
- my $f2 = sprintf("%02x", $f / 65536);
- my $f1 = sprintf("%02x", int($f % 65536) / 256);
- my $f0 = sprintf("%02x", $f % 256);
- $arg = sprintf("%.3f", (hex($f2)*65536+hex($f1)*256+hex($f0))/65536*26);
- Log3 $name, 3, "$name: Setting FREQ2..0 (0D,0E,0F) to $f2 $f1 $f0 = $arg MHz";
- SIGNALduino_AddSendQueue($hash,"W0F$f2");
- SIGNALduino_AddSendQueue($hash,"W10$f1");
- SIGNALduino_AddSendQueue($hash,"W11$f0");
- SIGNALduino_WriteInit($hash);
- } elsif( $cmd eq "bWidth" ) {
- SIGNALduino_AddSendQueue($hash,"C10");
- $hash->{getcmd}->{cmd} = "bWidth";
- $hash->{getcmd}->{arg} = $arg;
- } elsif( $cmd eq "rAmpl" ) {
- return "a numerical value between 24 and 42 is expected" if($arg !~ m/^\d+$/ || $arg < 24 || $arg > 42);
- my ($v, $w);
- for($v = 0; $v < @ampllist; $v++) {
- last if($ampllist[$v] > $arg);
- }
- $v = sprintf("%02d", $v-1);
- $w = $ampllist[$v];
- Log3 $name, 3, "$name: Setting AGCCTRL2 (1B) to $v / $w dB";
- SIGNALduino_AddSendQueue($hash,"W1D$v");
- SIGNALduino_WriteInit($hash);
- } elsif( $cmd eq "sens" ) {
- return "a numerical value between 4 and 16 is expected" if($arg !~ m/^\d+$/ || $arg < 4 || $arg > 16);
- my $w = int($arg/4)*4;
- my $v = sprintf("9%d",$arg/4-1);
- Log3 $name, 3, "$name: Setting AGCCTRL0 (1D) to $v / $w dB";
- SIGNALduino_AddSendQueue($hash,"W1F$v");
- SIGNALduino_WriteInit($hash);
- } elsif( substr($cmd,0,7) eq "patable" ) {
- my $paFreq = substr($cmd,8);
- my $pa = "x" . $patable{$paFreq}{$arg};
- Log3 $name, 3, "$name: Setting patable $paFreq $arg $pa";
- SIGNALduino_AddSendQueue($hash,$pa);
- SIGNALduino_WriteInit($hash);
- } elsif( $cmd eq "sendMsg" ) {
- Log3 $name, 5, "$name: sendmsg msg=$arg";
- my ($protocol,$data,$repeats,$clock,$frequency) = split("#",$arg);
- $protocol=~ s/[Pp](\d+)/$1/; # extract protocol num
- $repeats=~ s/[rR](\d+)/$1/; # extract repeat num
- $repeats=1 if (!defined($repeats));
- if (defined($clock) && substr($clock,0,1) eq "F") { # wenn es kein clock gibt, pruefen ob im clock eine frequency ist
- $clock=~ s/[F]([0-9a-fA-F]+$)/$1/;
- $frequency = $clock;
- $clock = undef;
- } else {
- $clock=~ s/[Cc](\d+)/$1/ if (defined($clock)); # extract ITClock num
- $frequency=~ s/[Ff]([0-9a-fA-F]+$)/$1/ if (defined($frequency));
- }
- if (exists($ProtocolListSIGNALduino{$protocol}{frequency}) && $hasCC1101 && !defined($frequency)) {
- $frequency = $ProtocolListSIGNALduino{$protocol}{frequency};
- }
- if (defined($frequency) && $hasCC1101) {
- $frequency="F=$frequency;";
- } else {
- $frequency="";
- }
-
- return "$name: sendmsg, unknown protocol: $protocol" if (!exists($ProtocolListSIGNALduino{$protocol}));
-
- #print ("data = $data \n");
- #print ("protocol = $protocol \n");
- #print ("repeats = $repeats \n");
-
- my %signalHash;
- my %patternHash;
- my $pattern="";
- my $cnt=0;
-
- my $sendData;
- if ($ProtocolListSIGNALduino{$protocol}{format} eq 'manchester')
- {
- #$clock = (map { $clock += $_ } @{$ProtocolListSIGNALduino{$protocol}{clockrange}}) / 2 if (!defined($clock));
-
- $clock += $_ for(@{$ProtocolListSIGNALduino{$protocol}{clockrange}});
- $clock = round($clock/2,0);
- if ($protocol == 43) {
- #$data =~ tr/0123456789ABCDEF/FEDCBA9876543210/;
- }
-
- my $intro = "";
- my $outro = "";
-
- $intro = $ProtocolListSIGNALduino{$protocol}{msgIntro} if ($ProtocolListSIGNALduino{$protocol}{msgIntro});
- $outro = $ProtocolListSIGNALduino{$protocol}{msgOutro}.";" if ($ProtocolListSIGNALduino{$protocol}{msgOutro});
- if ($intro ne "" || $outro ne "")
- {
- $intro = "SC;R=$repeats;" . $intro;
- $repeats = 0;
- }
- $sendData = $intro . "SM;" . ($repeats > 0 ? "R=$repeats;" : "") . "C=$clock;D=$data;" . $outro . $frequency; # SM;R=2;C=400;D=AFAFAF;
- Log3 $name, 5, "$name: sendmsg Preparing manchester protocol=$protocol, repeats=$repeats, clock=$clock data=$data";
- } else {
- if ($protocol == 3 || substr($data,0,2) eq "is") {
- if (substr($data,0,2) eq "is") {
- $data = substr($data,2); # is am Anfang entfernen
- }
- $data = SIGNALduino_ITV1_tristateToBit($data);
- Log3 $name, 5, "$name: sendmsg IT V1 convertet tristate to bits=$data";
- }
- if (!defined($clock)) {
- $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
- $clock=$ProtocolListSIGNALduino{$protocol}{clockabs} > 1 ?$ProtocolListSIGNALduino{$protocol}{clockabs}:$hash->{ITClock};
- }
- Log3 $name, 5, "$name: sendmsg Preparing rawsend command for protocol=$protocol, repeats=$repeats, clock=$clock bits=$data";
-
- foreach my $item (qw(sync start one zero float))
- {
- #print ("item= $item \n");
- next if (!exists($ProtocolListSIGNALduino{$protocol}{$item}));
-
- foreach my $p (@{$ProtocolListSIGNALduino{$protocol}{$item}})
- {
- #print (" p = $p \n");
-
- if (!exists($patternHash{$p}))
- {
- $patternHash{$p}=$cnt;
- $pattern.="P".$patternHash{$p}."=".$p*$clock.";";
- $cnt++;
- }
- $signalHash{$item}.=$patternHash{$p};
- #print (" signalHash{$item} = $signalHash{$item} \n");
- }
- }
- my @bits = split("", $data);
-
- my %bitconv = (1=>"one", 0=>"zero", 'D'=> "float");
- my $SignalData="D=";
-
- $SignalData.=$signalHash{sync} if (exists($signalHash{sync}));
- $SignalData.=$signalHash{start} if (exists($signalHash{start}));
- foreach my $bit (@bits)
- {
- next if (!exists($bitconv{$bit}));
- #Log3 $name, 5, "encoding $bit";
- $SignalData.=$signalHash{$bitconv{$bit}}; ## Add the signal to our data string
- }
- $sendData = "SR;R=$repeats;$pattern$SignalData;$frequency";
- }
-
- #SIGNALduino_SimpleWrite($hash, $sendData);
- SIGNALduino_AddSendQueue($hash,$sendData);
- Log3 $name, 4, "$name/set: sending via SendMsg: $sendData";
-
- } else {
- Log3 $name, 5, "$name/set: set $name $cmd $arg";
- #SIGNALduino_SimpleWrite($hash, $arg);
- return "Unknown argument $cmd, choose one of ". ReadingsVal($name,'cmd',' help me');
- }
- return undef;
- }
- #####################################
- sub
- SIGNALduino_Get($@)
- {
- my ($hash, @a) = @_;
- my $type = $hash->{TYPE};
- my $name = $hash->{NAME};
- return "$name is not active, may firmware is not suppoted, please flash or reset" if (exists($hash->{DevState}) && $hash->{DevState} ne 'initialized');
- #my $name = $a[0];
-
- Log3 $name, 5, "\"get $type\" needs at least one parameter" if(@a < 2);
- return "\"get $type\" needs at least one parameter" if(@a < 2);
- if(!defined($gets{$a[1]})) {
- my @cList = map { $_ =~ m/^(file|raw|ccreg)$/ ? $_ : "$_:noArg" } sort keys %gets;
- return "Unknown argument $a[1], choose one of " . join(" ", @cList);
- }
- my $arg = ($a[2] ? $a[2] : "");
- return "no command to send, get aborted." if (length($gets{$a[1]}[0]) == 0 && length($arg) == 0);
-
- if (($a[1] eq "ccconf" || $a[1] eq "ccreg" || $a[1] eq "ccpatable") && $hash->{version} && $hash->{version} !~ m/cc1101/) {
- return "This command is only available with a cc1101 receiver";
- }
-
- my ($msg, $err);
- if (IsDummy($name))
- {
- if ($arg =~ /^M[CSU];.*/)
- {
- $arg="\002$arg\003"; ## Add start end end marker if not already there
- Log3 $name, 5, "$name/msg adding start and endmarker to message";
-
- }
- if ($arg =~ /\002M.;.*;\003$/)
- {
- Log3 $name, 4, "$name/msg get raw: $arg";
- return SIGNALduino_Parse($hash, $hash, $hash->{NAME}, $arg);
- }
- else {
- my $arg2 = "";
- if ($arg =~ m/^version=/) { # set version
- $arg2 = substr($arg,8);
- $hash->{version} = "V " . $arg2;
- }
- elsif ($arg =~ m/^regexp=/) { # set fileRegexp for get raw messages from file
- $arg2 = substr($arg,7);
- $hash->{fileRegexp} = $arg2;
- delete($hash->{fileRegexp}) if (!$arg2);
- }
- elsif ($arg =~ m/^file=/) {
- $arg2 = substr($arg,5);
- my $n = 0;
- if (open(my $fh, '<', $arg2)) {
- my $fileRegexp = $hash->{fileRegexp};
- while (my $row = <$fh>) {
- if ($row =~ /.*\002M.;.*;\003$/) {
- chomp $row;
- $row =~ s/.*\002(M.;.*;)\003/$1/;
- if (!defined($fileRegexp) || $row =~ m/$fileRegexp/) {
- $n += 1;
- $row="\002$row\003";
- Log3 $name, 4, "$name/msg fileGetRaw: $row";
- SIGNALduino_Parse($hash, $hash, $hash->{NAME}, $row);
- }
- }
- }
- return $n . " raw Nachrichten eingelesen";
- } else {
- return "Could not open file $arg2";
- }
- }
- elsif ($arg eq '?') {
- my $ret;
-
- $ret = "dummy get raw\n\n";
- $ret .= "raw message e.g. MS;P0=-392;P1=...\n";
- $ret .= "dispatch message e.g. P7#6290DCF37\n";
- $ret .= "version=x.x.x sets version. e.g. (version=3.2.0) to get old MC messages\n";
- $ret .= "regexp= set fileRegexp for get raw messages from file. e.g. regexp=^MC\n";
- $ret .= "file= gets raw messages from file in the fhem directory\n";
- return $ret;
- }
- else {
- Log3 $name, 4, "$name/msg get dispatch: $arg";
- Dispatch($hash, $arg, undef);
- }
- return "";
- }
- }
- return "No $a[1] for dummies" if(IsDummy($name));
- Log3 $name, 5, "$name: command for gets: " . $gets{$a[1]}[0] . " " . $arg;
- if ($a[1] eq "raw")
- {
- # Dirty hack to check and modify direct communication from logical modules with hardware
- if ($arg =~ /^is.*/ && length($arg) == 34)
- {
- # Arctec protocol
- Log3 $name, 5, "$name: calling set :sendmsg P17;R6#".substr($arg,2);
-
- SIGNALduino_Set($hash,$name,"sendMsg","P17#",substr($arg,2),"#R6");
- return "$a[0] $a[1] => $arg";
- }
-
- }
- elsif ($a[1] eq "protocolIDs")
- {
- my $id;
- my $ret;
- my $s;
- my $moduleId;
- my @IdList = ();
-
- foreach $id (keys %ProtocolListSIGNALduino)
- {
- next if ($id eq 'id');
- push (@IdList, $id);
- }
- @IdList = sort { $a <=> $b } @IdList;
-
- $ret = " ID modulname protocolname # comment\n\n";
-
- foreach $id (@IdList)
- {
- $ret .= sprintf("%3s",$id) . " ";
-
- if (exists ($ProtocolListSIGNALduino{$id}{format}) && $ProtocolListSIGNALduino{$id}{format} eq "manchester")
- {
- $ret .= "MC";
- }
- elsif (exists $ProtocolListSIGNALduino{$id}{sync})
- {
- $ret .= "MS";
- }
- elsif (exists ($ProtocolListSIGNALduino{$id}{clockabs}))
- {
- $ret .= "MU";
- }
-
- if (exists ($ProtocolListSIGNALduino{$id}{clientmodule}))
- {
- $moduleId .= "$id,";
- $s = $ProtocolListSIGNALduino{$id}{clientmodule};
- if (length($s) < 15)
- {
- $s .= substr(" ",length($s) - 15);
- }
- $ret .= " $s";
- }
- else
- {
- $ret .= " ";
- }
-
- if (exists ($ProtocolListSIGNALduino{$id}{name}))
- {
- $ret .= " $ProtocolListSIGNALduino{$id}{name}";
- }
-
- if (exists ($ProtocolListSIGNALduino{$id}{comment}))
- {
- $ret .= " # $ProtocolListSIGNALduino{$id}{comment}";
- }
-
- $ret .= "\n";
- }
- #$moduleId =~ s/,$//;
-
- return "$a[1]: \n\n$ret\n";
- #return "$a[1]: \n\n$ret\nIds with modules: $moduleId";
- }
-
- #SIGNALduino_SimpleWrite($hash, $gets{$a[1]}[0] . $arg);
- SIGNALduino_AddSendQueue($hash, $gets{$a[1]}[0] . $arg);
- $hash->{getcmd}->{cmd}=$a[1];
- $hash->{getcmd}->{asyncOut}=$hash->{CL};
- $hash->{getcmd}->{timenow}=time();
-
- 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
- }
- sub SIGNALduino_parseResponse($$$)
- {
- my $hash = shift;
- my $cmd = shift;
- my $msg = shift;
- my $name=$hash->{NAME};
-
- $msg =~ s/[\r\n]//g;
- if($cmd eq "cmds")
- { # nice it up
- $msg =~ s/$name cmds =>//g;
- $msg =~ s/.*Use one of//g;
- }
- elsif($cmd eq "uptime")
- { # decode it
- #$msg = hex($msg); # /125; only for col or coc
- $msg = sprintf("%d %02d:%02d:%02d", $msg/86400, ($msg%86400)/3600, ($msg%3600)/60, $msg%60);
- }
- elsif($cmd eq "ccregAll")
- {
- $msg =~ s/ /\n/g;
- $msg = "\n\n" . $msg
- }
- elsif($cmd eq "ccconf")
- {
- my (undef,$str) = split('=', $msg);
- my $var;
- my %r = ( "0D"=>1,"0E"=>1,"0F"=>1,"10"=>1,"11"=>1,"1B"=>1,"1D"=>1 );
- $msg = "";
- foreach my $a (sort keys %r) {
- $var = substr($str,(hex($a)-13)*2, 2);
- $r{$a} = hex($var);
- }
- $msg = sprintf("freq:%.3fMHz bWidth:%dKHz rAmpl:%ddB sens:%ddB (DataRate:%.2fBaud)",
- 26*(($r{"0D"}*256+$r{"0E"})*256+$r{"0F"})/65536, #Freq
- 26000/(8 * (4+(($r{"10"}>>4)&3)) * (1 << (($r{"10"}>>6)&3))), #Bw
- $ampllist[$r{"1B"}&7], #rAmpl
- 4+4*($r{"1D"}&3), #Sens
- ((256+$r{"11"})*(2**($r{"10"} & 15 )))*26000000/(2**28) #DataRate
- );
- }
- elsif($cmd eq "bWidth") {
- my $val = hex(substr($msg,6));
- my $arg = $hash->{getcmd}->{arg};
- my $ob = $val & 0x0f;
-
- my ($bits, $bw) = (0,0);
- OUTERLOOP:
- for (my $e = 0; $e < 4; $e++) {
- for (my $m = 0; $m < 4; $m++) {
- $bits = ($e<<6)+($m<<4);
- $bw = int(26000/(8 * (4+$m) * (1 << $e))); # KHz
- last OUTERLOOP if($arg >= $bw);
- }
- }
- $ob = sprintf("%02x", $ob+$bits);
- $msg = "Setting MDMCFG4 (10) to $ob = $bw KHz";
- Log3 $name, 3, "$name/msg parseResponse bWidth: Setting MDMCFG4 (10) to $ob = $bw KHz";
- delete($hash->{getcmd});
- SIGNALduino_AddSendQueue($hash,"W12$ob");
- SIGNALduino_WriteInit($hash);
- }
- elsif($cmd eq "ccpatable") {
- my $CC1101Frequency = "433";
- if (defined($hash->{cc1101_frequency})) {
- $CC1101Frequency = $hash->{cc1101_frequency};
- }
- my $dBn = substr($msg,9,2);
- Log3 $name, 3, "$name/msg parseResponse patable: $dBn";
- foreach my $dB (keys %{ $patable{$CC1101Frequency} }) {
- if ($dBn eq $patable{$CC1101Frequency}{$dB}) {
- Log3 $name, 5, "$name/msg parseResponse patable: $dB";
- $msg .= " => $dB";
- last;
- }
- }
- # $msg .= "\n\n$CC1101Frequency MHz\n\n";
- # foreach my $dB (keys $patable{$CC1101Frequency})
- # {
- # $msg .= "$patable{$CC1101Frequency}{$dB} $dB\n";
- # }
- }
-
- return $msg;
- }
- #####################################
- sub
- SIGNALduino_ResetDevice($)
- {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- Log3 $hash, 3, "$name reset";
- DevIo_CloseDev($hash);
- my $ret = DevIo_OpenDev($hash, 0, "SIGNALduino_DoInit", 'SIGNALduino_Connect');
- return $ret;
- }
- #####################################
- sub
- SIGNALduino_CloseDevice($)
- {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- Log3 $hash, 2, "$name closed";
- RemoveInternalTimer($hash);
- DevIo_CloseDev($hash);
- readingsSingleUpdate($hash, "state", "closed", 1);
-
- return undef;
- }
- #####################################
- sub
- SIGNALduino_DoInit($)
- {
- my $hash = shift;
- my $name = $hash->{NAME};
- my $err;
- my $msg = undef;
- my ($ver, $try) = ("", 0);
- #Dirty hack to allow initialisation of DirectIO Device for some debugging and tesing
- Log3 $hash, 1, "$name/define: ".$hash->{DEF};
-
- delete($hash->{disConnFlag}) if defined($hash->{disConnFlag});
-
- RemoveInternalTimer("HandleWriteQueue:$name");
- @{$hash->{QUEUE}} = ();
- $hash->{sendworking} = 0;
-
- # if (($hash->{DEF} !~ m/\@DirectIO/) and ($hash->{DEF} !~ m/none/) )
- if (($hash->{DEF} !~ m/\@directio/) and ($hash->{DEF} !~ m/none/) )
- {
- Log3 $hash, 1, "$name/init: ".$hash->{DEF};
- $hash->{initretry} = 0;
- RemoveInternalTimer($hash);
-
- #SIGNALduino_SimpleWrite($hash, "XQ"); # Disable receiver
- InternalTimer(gettimeofday() + SDUINO_INIT_WAIT_XQ, "SIGNALduino_SimpleWrite_XQ", $hash, 0);
-
- InternalTimer(gettimeofday() + SDUINO_INIT_WAIT, "SIGNALduino_StartInit", $hash, 0);
- }
- # Reset the counter
- delete($hash->{XMIT_TIME});
- delete($hash->{NR_CMD_LAST_H});
- return;
- return undef;
- }
- # Disable receiver
- sub SIGNALduino_SimpleWrite_XQ($) {
- my ($hash) = @_;
- my $name = $hash->{NAME};
-
- Log3 $hash, 3, "$name/init: disable receiver (XQ)";
- SIGNALduino_SimpleWrite($hash, "XQ");
- #DevIo_SimpleWrite($hash, "XQ\n",2);
- }
- sub SIGNALduino_StartInit($)
- {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- $hash->{version} = undef;
-
- Log3 $name,3 , "$name/init: get version, retry = " . $hash->{initretry};
- if ($hash->{initretry} >= SDUINO_INIT_MAXRETRY) {
- $hash->{DevState} = 'INACTIVE';
- # einmaliger reset, wenn danach immer noch 'init retry count reached', dann SIGNALduino_CloseDevice()
- if (!defined($hash->{initResetFlag})) {
- Log3 $name,2 , "$name/init retry count reached. Reset";
- $hash->{initResetFlag} = 1;
- SIGNALduino_ResetDevice($hash);
- } else {
- Log3 $name,2 , "$name/init retry count reached. Closed";
- SIGNALduino_CloseDevice($hash);
- }
- return;
- }
- else {
- $hash->{getcmd}->{cmd} = "version";
- SIGNALduino_SimpleWrite($hash, "V");
- #DevIo_SimpleWrite($hash, "V\n",2);
- $hash->{DevState} = 'waitInit';
- RemoveInternalTimer($hash);
- InternalTimer(gettimeofday() + SDUINO_CMD_TIMEOUT, "SIGNALduino_CheckCmdResp", $hash, 0);
- }
- }
- ####################
- sub SIGNALduino_CheckCmdResp($)
- {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- my $msg = undef;
- my $ver;
-
- if ($hash->{version}) {
- $ver = $hash->{version};
- if ($ver !~ m/SIGNAL(duino|ESP)/) {
- $msg = "$name: Not an SIGNALduino device, setting attribute dummy=1 got for V: $ver";
- Log3 $hash, 1, $msg;
- readingsSingleUpdate($hash, "state", "no SIGNALduino found", 1);
- $hash->{DevState} = 'INACTIVE';
- SIGNALduino_CloseDevice($hash);
- }
- elsif($ver =~ m/^V 3\.1\./) {
- $msg = "$name: Version of your arduino is not compatible, pleas flash new firmware. (device closed) Got for V: $ver";
- readingsSingleUpdate($hash, "state", "unsupported firmware found", 1);
- Log3 $hash, 1, $msg;
- $hash->{DevState} = 'INACTIVE';
- SIGNALduino_CloseDevice($hash);
- }
- else {
- readingsSingleUpdate($hash, "state", "opened", 1);
- Log3 $name, 2, "$name: initialized. " . SDUINO_VERSION;
- $hash->{DevState} = 'initialized';
- delete($hash->{initResetFlag}) if defined($hash->{initResetFlag});
- SIGNALduino_SimpleWrite($hash, "XE"); # Enable receiver
- #DevIo_SimpleWrite($hash, "XE\n",2);
- Log3 $hash, 3, "$name/init: enable receiver (XE)";
- delete($hash->{initretry});
- # initialize keepalive
- $hash->{keepalive}{ok} = 0;
- $hash->{keepalive}{retry} = 0;
- InternalTimer(gettimeofday() + SDUINO_KEEPALIVE_TIMEOUT, "SIGNALduino_KeepAlive", $hash, 0);
- }
- }
- else {
- delete($hash->{getcmd});
- $hash->{initretry} ++;
- #InternalTimer(gettimeofday()+1, "SIGNALduino_StartInit", $hash, 0);
- SIGNALduino_StartInit($hash);
- }
- }
- #####################################
- # Check if the 1% limit is reached and trigger notifies
- sub
- SIGNALduino_XmitLimitCheck($$)
- {
- my ($hash,$fn) = @_;
-
-
- return if ($fn !~ m/^(is|SR).*/);
- my $now = time();
- if(!$hash->{XMIT_TIME}) {
- $hash->{XMIT_TIME}[0] = $now;
- $hash->{NR_CMD_LAST_H} = 1;
- return;
- }
- my $nowM1h = $now-3600;
- my @b = grep { $_ > $nowM1h } @{$hash->{XMIT_TIME}};
- if(@b > 163) { # Maximum nr of transmissions per hour (unconfirmed).
- my $name = $hash->{NAME};
- Log3 $name, 2, "SIGNALduino TRANSMIT LIMIT EXCEEDED";
- DoTrigger($name, "TRANSMIT LIMIT EXCEEDED");
- } else {
- push(@b, $now);
- }
- $hash->{XMIT_TIME} = \@b;
- $hash->{NR_CMD_LAST_H} = int(@b);
- }
- #####################################
- ## API to logical modules: Provide as Hash of IO Device, type of function ; command to call ; message to send
- sub
- SIGNALduino_Write($$$)
- {
- my ($hash,$fn,$msg) = @_;
- my $name = $hash->{NAME};
- $fn="RAW" if $fn eq "";
- Log3 $name, 5, "$name/write: adding to queue $fn $msg";
- #SIGNALduino_SimpleWrite($hash, $bstring);
-
- SIGNALduino_Set($hash,$name,$fn,$msg);
- #SIGNALduino_AddSendQueue($hash,$bstring);
-
- }
- sub SIGNALduino_AddSendQueue($$)
- {
- my ($hash, $msg) = @_;
- my $name = $hash->{NAME};
-
- push(@{$hash->{QUEUE}}, $msg);
-
- #Log3 $hash , 5, Dumper($hash->{QUEUE});
-
- Log3 $hash, 5,"AddSendQueue: " . $hash->{NAME} . ": $msg (" . @{$hash->{QUEUE}} . ")";
- InternalTimer(gettimeofday() + 0.1, "SIGNALduino_HandleWriteQueue", "HandleWriteQueue:$name") if (@{$hash->{QUEUE}} == 1 && $hash->{sendworking} == 0);
- }
- sub
- SIGNALduino_SendFromQueue($$)
- {
- my ($hash, $msg) = @_;
- my $name = $hash->{NAME};
-
- if($msg ne "") {
- SIGNALduino_XmitLimitCheck($hash,$msg);
- #DevIo_SimpleWrite($hash, $msg . "\n", 2);
- $hash->{sendworking} = 1;
- SIGNALduino_SimpleWrite($hash,$msg);
- if ($msg =~ m/^S(R|C|M);/) {
- $hash->{getcmd}->{cmd} = 'sendraw';
- Log3 $hash, 4, "$name SendrawFromQueue: msg=$msg"; # zu testen der Queue, kann wenn es funktioniert auskommentiert werden
- }
- elsif ($msg eq "C99") {
- $hash->{getcmd}->{cmd} = 'ccregAll';
- }
- }
- ##############
- # Write the next buffer not earlier than 0.23 seconds
- # else it will be sent too early by the SIGNALduino, resulting in a collision, or may the last command is not finished
-
- if (defined($hash->{getcmd}->{cmd}) && $hash->{getcmd}->{cmd} eq 'sendraw') {
- InternalTimer(gettimeofday() + SDUINO_WRITEQUEUE_TIMEOUT, "SIGNALduino_HandleWriteQueue", "HandleWriteQueue:$name");
- } else {
- InternalTimer(gettimeofday() + SDUINO_WRITEQUEUE_NEXT, "SIGNALduino_HandleWriteQueue", "HandleWriteQueue:$name");
- }
- }
- ####################################
- sub
- SIGNALduino_HandleWriteQueue($)
- {
- my($param) = @_;
- my(undef,$name) = split(':', $param);
- my $hash = $defs{$name};
-
- #my @arr = @{$hash->{QUEUE}};
-
- $hash->{sendworking} = 0; # es wurde gesendet
-
- if (defined($hash->{getcmd}->{cmd}) && $hash->{getcmd}->{cmd} eq 'sendraw') {
- Log3 $name, 4, "$name/HandleWriteQueue: sendraw no answer (timeout)";
- delete($hash->{getcmd});
- }
-
- if(@{$hash->{QUEUE}}) {
- my $msg= shift(@{$hash->{QUEUE}});
- if($msg eq "") {
- SIGNALduino_HandleWriteQueue("x:$name");
- } else {
- SIGNALduino_SendFromQueue($hash, $msg);
- }
- } else {
- Log3 $name, 4, "$name/HandleWriteQueue: nothing to send, stopping timer";
- RemoveInternalTimer("HandleWriteQueue:$name");
- }
- }
- #####################################
- # called from the global loop, when the select for hash->{FD} reports data
- sub
- SIGNALduino_Read($)
- {
- my ($hash) = @_;
- my $buf = DevIo_SimpleRead($hash);
- return "" if(!defined($buf));
- my $name = $hash->{NAME};
- my $debug = AttrVal($name,"debug",0);
- my $SIGNALduinodata = $hash->{PARTIAL};
- Log3 $name, 5, "$name/RAW READ: $SIGNALduinodata/$buf" if ($debug);
- $SIGNALduinodata .= $buf;
- while($SIGNALduinodata =~ m/\n/) {
- my $rmsg;
- ($rmsg,$SIGNALduinodata) = split("\n", $SIGNALduinodata, 2);
- $rmsg =~ s/\r//;
-
- if ($rmsg =~ m/^\002(M(s|u);.*;)\003/) {
- $rmsg =~ s/^\002//; # \002 am Anfang entfernen
- my @msg_parts = split(";",$rmsg);
- my $m0;
- my $mnr0;
- my $m1;
- my $mL;
- my $mH;
- my $part = "";
- my $partD;
-
- foreach my $msgPart (@msg_parts) {
- $m0 = substr($msgPart,0,1);
- $mnr0 = ord($m0);
- $m1 = substr($msgPart,1);
- if ($m0 eq "M") {
- $part .= "M" . uc($m1) . ";";
- }
- elsif ($mnr0 > 127) {
- $part .= "P" . sprintf("%u", ($mnr0 & 7)) . "=";
- if (length($m1) == 2) {
- $mL = ord(substr($m1,0,1)) & 127; # Pattern low
- $mH = ord(substr($m1,1,1)) & 127; # Pattern high
- if (($mnr0 & 0b00100000) != 0) { # Vorzeichen 0b00100000 = 32
- $part .= "-";
- }
- if ($mnr0 & 0b00010000) { # Bit 7 von Pattern low
- $mL += 128;
- }
- $part .= ($mH * 256) + $mL;
- }
- $part .= ";";
- }
- elsif (($m0 eq "D" || $m0 eq "d") && length($m1) > 0) {
- my @arrayD = split(//, $m1);
- $part .= "D=";
- $partD = "";
- foreach my $D (@arrayD) {
- $mH = ord($D) >> 4;
- $mL = ord($D) & 7;
- $partD .= "$mH$mL";
- }
- #Log3 $name, 3, "$name/msg READredu1$m0: $partD";
- if ($m0 eq "d") {
- $partD =~ s/.$//; # letzte Ziffer entfernen wenn Anzahl der Ziffern ungerade
- }
- $partD =~ s/^8//; # 8 am Anfang entfernen
- #Log3 $name, 3, "$name/msg READredu2$m0: $partD";
- $part = $part . $partD . ';';
- }
- elsif (($m0 eq "C" || $m0 eq "S") && length($m1) == 1) {
- $part .= "$m0" . "P=$m1;";
- }
- elsif ($m1 =~ m/^[0-9A-Z]{1,2}$/) { # bei 1 oder 2 Hex Ziffern nach Dez wandeln
- $part .= "$m0=" . hex($m1) . ";";
- }
- elsif ($m0 =~m/[0-9a-zA-Z]/) {
- $part .= "$m0";
- if ($m1 ne "") {
- $part .= "=$m1";
- }
- $part .= ";";
- }
- }
- Log3 $name, 4, "$name/msg READredu: $part";
- $rmsg = "\002$part\003";
- }
- else {
- Log3 $name, 4, "$name/msg READ: $rmsg";
- }
- if ( $rmsg && !SIGNALduino_Parse($hash, $hash, $name, $rmsg) && defined($hash->{getcmd}) && defined($hash->{getcmd}->{cmd}))
- {
- my $regexp;
- if ($hash->{getcmd}->{cmd} eq 'sendraw') {
- $regexp = '^S(R|C|M);';
- }
- elsif ($hash->{getcmd}->{cmd} eq 'ccregAll') {
- $regexp = '^ccreg 00:';
- }
- elsif ($hash->{getcmd}->{cmd} eq 'bWidth') {
- $regexp = '^C.* = .*';
- }
- else {
- $regexp = $gets{$hash->{getcmd}->{cmd}}[1];
- }
- if(!defined($regexp) || $rmsg =~ m/$regexp/) {
- if (defined($hash->{keepalive})) {
- $hash->{keepalive}{ok} = 1;
- $hash->{keepalive}{retry} = 0;
- }
- Log3 $name, 5, "$name/msg READ: regexp=$regexp cmd=$hash->{getcmd}->{cmd} msg=$rmsg";
-
- if ($hash->{getcmd}->{cmd} eq 'version') {
- my $msg_start = index($rmsg, 'V 3.');
- if ($msg_start > 0) {
- $rmsg = substr($rmsg, $msg_start);
- Log3 $name, 4, "$name/read: cut chars at begin. msgstart = $msg_start msg = $rmsg";
- }
- $hash->{version} = $rmsg;
- if (defined($hash->{DevState}) && $hash->{DevState} eq 'waitInit') {
- RemoveInternalTimer($hash);
- SIGNALduino_CheckCmdResp($hash);
- }
- }
- if ($hash->{getcmd}->{cmd} eq 'sendraw') {
- # zu testen der sendeQueue, kann wenn es funktioniert auf verbose 5
- Log3 $name, 4, "$name/read sendraw answer: $rmsg";
- delete($hash->{getcmd});
- RemoveInternalTimer("HandleWriteQueue:$name");
- SIGNALduino_HandleWriteQueue("x:$name");
- }
- else {
- $rmsg = SIGNALduino_parseResponse($hash,$hash->{getcmd}->{cmd},$rmsg);
- if (defined($hash->{getcmd}) && $hash->{getcmd}->{cmd} ne 'ccregAll') {
- readingsSingleUpdate($hash, $hash->{getcmd}->{cmd}, $rmsg, 0);
- }
- if (defined($hash->{getcmd}->{asyncOut})) {
- #Log3 $name, 4, "$name/msg READ: asyncOutput";
- my $ao = asyncOutput( $hash->{getcmd}->{asyncOut}, $hash->{getcmd}->{cmd}.": " . $rmsg );
- }
- delete($hash->{getcmd});
- }
- } else {
- Log3 $name, 4, "$name/msg READ: Received answer ($rmsg) for ". $hash->{getcmd}->{cmd}." does not match $regexp";
- }
- }
- }
- $hash->{PARTIAL} = $SIGNALduinodata;
- }
- sub SIGNALduino_KeepAlive($){
- my ($hash) = @_;
- my $name = $hash->{NAME};
-
- return if ($hash->{DevState} eq 'disconnected');
-
- #Log3 $name,4 , "$name/KeepAliveOk: " . $hash->{keepalive}{ok};
- if (!$hash->{keepalive}{ok}) {
- delete($hash->{getcmd});
- if ($hash->{keepalive}{retry} >= SDUINO_KEEPALIVE_MAXRETRY) {
- Log3 $name,3 , "$name/keepalive not ok, retry count reached. Reset";
- $hash->{DevState} = 'INACTIVE';
- SIGNALduino_ResetDevice($hash);
- return;
- }
- else {
- my $logLevel = 3;
- $hash->{keepalive}{retry} ++;
- if ($hash->{keepalive}{retry} == 1) {
- $logLevel = 4;
- }
- Log3 $name, $logLevel, "$name/KeepAlive not ok, retry = " . $hash->{keepalive}{retry} . " -> get ping";
- $hash->{getcmd}->{cmd} = "ping";
- SIGNALduino_AddSendQueue($hash, "P");
- #SIGNALduino_SimpleWrite($hash, "P");
- }
- }
- else {
- Log3 $name,4 , "$name/keepalive ok, retry = " . $hash->{keepalive}{retry};
- }
- $hash->{keepalive}{ok} = 0;
-
- InternalTimer(gettimeofday() + SDUINO_KEEPALIVE_TIMEOUT, "SIGNALduino_KeepAlive", $hash);
- }
- ### Helper Subs >>>
- ## Parses a HTTP Response for example for flash via http download
- sub SIGNALduino_ParseHttpResponse
- {
-
- my ($param, $err, $data) = @_;
- my $hash = $param->{hash};
- my $name = $hash->{NAME};
- if($err ne "") # wenn ein Fehler bei der HTTP Abfrage aufgetreten ist
- {
- Log3 $name, 3, "error while requesting ".$param->{url}." - $err"; # Eintrag fürs Log
- }
- elsif($param->{code} eq "200" && $data ne "") # wenn die Abfrage erfolgreich war ($data enthält die Ergebnisdaten des HTTP Aufrufes)
- {
-
- Log3 $name, 3, "url ".$param->{url}." returned: ".length($data)." bytes Data"; # Eintrag fürs Log
-
- if ($param->{command} eq "flash")
- {
- my $filename;
-
- if ($param->{httpheader} =~ /Content-Disposition: attachment;.?filename=\"?([-+.\w]+)?\"?/)
- {
- $filename = $1;
- } else { # Filename via path if not specifyied via Content-Disposition
- ($filename = $param->{path}) =~s/.*\///;
- }
-
- Log3 $name, 3, "$name: Downloaded $filename firmware from ".$param->{host};
- Log3 $name, 5, "$name: Header = ".$param->{httpheader};
-
-
- $filename = "FHEM/firmware/" . $filename;
- open(my $file, ">", $filename) or die $!;
- print $file $data;
- close $file;
-
- # Den Flash Befehl mit der soebene heruntergeladenen Datei ausführen
- #Log3 $name, 3, "calling set ".$param->{command}." $filename"; # Eintrag fürs Log
- SIGNALduino_Set($hash,$name,$param->{command},$filename); # $hash->{SetFn}
-
- }
- } else {
- Log3 $name, 3, "undefined error while requesting ".$param->{url}." - $err - code=".$param->{code}; # Eintrag fürs Log
- }
- }
- sub SIGNALduino_splitMsg
- {
- my $txt = shift;
- my $delim = shift;
- my @msg_parts = split(/$delim/,$txt);
-
- return @msg_parts;
- }
- # $value - $set <= $tolerance
- sub SIGNALduino_inTol($$$)
- {
- #Debug "sduino abs \($_[0] - $_[1]\) <= $_[2] ";
- return (abs($_[0]-$_[1])<=$_[2]);
- }
- # - - - - - - - - - - - -
- #=item SIGNALduino_PatternExists()
- #This functons, needs reference to $hash, @array of values to search and %patternList where to find the matches.
- #
- # 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
- # =cut
- # 01232323242423 while ($message =~ /$pstr/g) { $count++ }
- sub SIGNALduino_PatternExists
- {
- my ($hash,$search,$patternList,$data) = @_;
- #my %patternList=$arg3;
- #Debug "plist: ".Dumper($patternList) if($debug);
- #Debug "searchlist: ".Dumper($search) if($debug);
-
- my $searchpattern;
- my $valid=1;
- my @pstr;
- my $debug = AttrVal($hash->{NAME},"debug",0);
-
- my $i=0;
-
- my $maxcol=0;
-
- foreach $searchpattern (@{$search}) # z.B. [1, -4]
- {
- #my $patt_id;
- # Calculate tolernace for search
- #my $tol=abs(abs($searchpattern)>=2 ?$searchpattern*0.3:$searchpattern*1.5);
- 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
-
- Debug "tol: looking for ($searchpattern +- $tol)" if($debug);
-
- my %pattern_gap ; #= {};
- # Find and store the gap of every pattern, which is in tolerance
- %pattern_gap = map { $_ => abs($patternList->{$_}-$searchpattern) } grep { abs($patternList->{$_}-$searchpattern) <= $tol} (keys %$patternList);
- if (scalar keys %pattern_gap > 0)
- {
- Debug "index => gap in tol (+- $tol) of pulse ($searchpattern) : ".Dumper(\%pattern_gap) if($debug);
- # Extract fist pattern, which is nearst to our searched value
- my @closestidx = (sort {$pattern_gap{$a} <=> $pattern_gap{$b}} keys %pattern_gap);
-
- my $idxstr="";
- my $r=0;
-
- while (my ($item) = splice(@closestidx, 0, 1))
- {
- $pstr[$i][$r]=$item;
- $r++;
- Debug "closest pattern has index: $item" if($debug);
- }
- $valid=1;
- } else {
- # search is not found, return -1
- return -1;
- last;
- }
- $i++;
- #return ($valid ? $pstr : -1); # return $pstr if $valid or -1
-
- #foreach $patt_id (keys %$patternList) {
- #Debug "$patt_id. chk ->intol $patternList->{$patt_id} $searchpattern $tol";
- #$valid = SIGNALduino_inTol($patternList->{$patt_id}, $searchpattern, $tol);
- #if ( $valid) #one pulse found in tolerance, search next one
- #{
- # $pstr="$pstr$patt_id";
- # # provide this index for further lookup table -> {$patt_id = $searchpattern}
- # Debug "pulse found";
- # last ; ## Exit foreach loop if searched pattern matches pattern in list
- #}
- #}
- #last if (!$valid); ## Exit loop if a complete iteration has not found anything
- }
- my @results = ('');
-
- foreach my $subarray (@pstr)
- {
- @results = map {my $res = $_; map $res.$_, @$subarray } @results;
- }
-
- foreach my $search (@results)
- {
- Debug "looking for substr $search" if($debug);
-
- return $search if (index( ${$data}, $search) >= 0);
- }
-
- return -1;
-
- #return ($valid ? @results : -1); # return @pstr if $valid or -1
- }
- #SIGNALduino_MatchSignalPattern{$hash,@array, %hash, @array, $scalar}; not used >v3.1.3
- sub SIGNALduino_MatchSignalPattern($\@\%\@$){
- my ( $hash, $signalpattern, $patternList, $data_array, $idx) = @_;
- my $name = $hash->{NAME};
- #print Dumper($patternList);
- #print Dumper($idx);
- #Debug Dumper($signalpattern) if ($debug);
- my $tol="0.2"; # Tolerance factor
- my $found=0;
- my $debug = AttrVal($hash->{NAME},"debug",0);
-
- foreach ( @{$signalpattern} )
- {
- #Debug " $idx check: ".$patternList->{$data_array->[$idx]}." == ".$_;
- Debug "$name: idx: $idx check: abs(". $patternList->{$data_array->[$idx]}." - ".$_.") > ". ceil(abs($patternList->{$data_array->[$idx]}*$tol)) if ($debug);
-
- #print "\n";;
- #if ($patternList->{$data_array->[$idx]} ne $_ )
- ### Nachkommastelle von ceil!!!
- if (!defined( $patternList->{$data_array->[$idx]})){
- Debug "$name: Error index ($idx) does not exist!!" if ($debug);
- return -1;
- }
- if (abs($patternList->{$data_array->[$idx]} - $_) > ceil(abs($patternList->{$data_array->[$idx]}*$tol)))
- {
- return -1; ## Pattern does not match, return -1 = not matched
- }
- $found=1;
- $idx++;
- }
- if ($found)
- {
- return $idx; ## Return new Index Position
- }
-
- }
- sub SIGNALduino_b2h {
- my $num = shift;
- my $WIDTH = 4;
- my $index = length($num) - $WIDTH;
- my $hex = '';
- do {
- my $width = $WIDTH;
- if ($index < 0) {
- $width += $index;
- $index = 0;
- }
- my $cut_string = substr($num, $index, $width);
- $hex = sprintf('%X', oct("0b$cut_string")) . $hex;
- $index -= $WIDTH;
- } while ($index > (-1 * $WIDTH));
- return $hex;
- }
- sub SIGNALduino_Split_Message($$)
- {
- my $rmsg = shift;
- my $name = shift;
- my %patternList;
- my $clockidx;
- my $syncidx;
- my $rawData;
- my $clockabs;
- my $mcbitnum;
- my $rssi;
-
- my @msg_parts = SIGNALduino_splitMsg($rmsg,';'); ## Split message parts by ";"
- my %ret;
- my $debug = AttrVal($name,"debug",0);
-
- foreach (@msg_parts)
- {
- #Debug "$name: checking msg part:( $_ )" if ($debug);
- if ($_ =~ m/^MS/ or $_ =~ m/^MC/ or $_ =~ m/^MU/) #### Synced Message start
- {
- $ret{messagetype} = $_;
- }
- elsif ($_ =~ m/^P\d=-?\d{2,}/ or $_ =~ m/^[SL][LH]=-?\d{2,}/) #### Extract Pattern List from array
- {
- $_ =~ s/^P+//;
- $_ =~ s/^P\d//;
- my @pattern = split(/=/,$_);
-
- $patternList{$pattern[0]} = $pattern[1];
- Debug "$name: extracted pattern @pattern \n" if ($debug);
- }
- elsif($_ =~ m/D=\d+/ or $_ =~ m/^D=[A-F0-9]+/) #### Message from array
- {
- $_ =~ s/D=//;
- $rawData = $_ ;
- Debug "$name: extracted data $rawData\n" if ($debug);
- $ret{rawData} = $rawData;
- }
- elsif($_ =~ m/^SP=\d{1}/) #### Sync Pulse Index
- {
- (undef, $syncidx) = split(/=/,$_);
- Debug "$name: extracted syncidx $syncidx\n" if ($debug);
- #return undef if (!defined($patternList{$syncidx}));
- $ret{syncidx} = $syncidx;
- }
- elsif($_ =~ m/^CP=\d{1}/) #### Clock Pulse Index
- {
- (undef, $clockidx) = split(/=/,$_);
- Debug "$name: extracted clockidx $clockidx\n" if ($debug);;
- #return undef if (!defined($patternList{$clockidx}));
- $ret{clockidx} = $clockidx;
- }
- elsif($_ =~ m/^L=\d/) #### MC bit length
- {
- (undef, $mcbitnum) = split(/=/,$_);
- Debug "$name: extracted number of $mcbitnum bits\n" if ($debug);;
- $ret{mcbitnum} = $mcbitnum;
- }
-
- elsif($_ =~ m/^C=\d+/) #### Message from array
- {
- $_ =~ s/C=//;
- $clockabs = $_ ;
- Debug "$name: extracted absolute clock $clockabs \n" if ($debug);
- $ret{clockabs} = $clockabs;
- }
- elsif($_ =~ m/^R=\d+/) ### RSSI ###
- {
- $_ =~ s/R=//;
- $rssi = $_ ;
- Debug "$name: extracted RSSI $rssi \n" if ($debug);
- $ret{rssi} = $rssi;
- } else {
- Debug "$name: unknown Message part $_" if ($debug);;
- }
- #print "$_\n";
- }
- $ret{pattern} = {%patternList};
- return %ret;
- }
- # Function which dispatches a message if needed.
- sub SIGNALduno_Dispatch($$$$$)
- {
- my ($hash, $rmsg, $dmsg, $rssi, $id) = @_;
- my $name = $hash->{NAME};
-
- if (!defined($dmsg))
- {
- Log3 $name, 5, "$name Dispatch: dmsg is undef. Skipping dispatch call";
- return;
- }
-
- #Log3 $name, 5, "$name: Dispatch DMSG: $dmsg";
-
- my $DMSGgleich = 1;
- if ($dmsg eq $hash->{LASTDMSG}) {
- Log3 $name, SDUINO_DISPATCH_VERBOSE, "$name Dispatch: $dmsg, test gleich";
- } else {
- if (defined($hash->{DoubleMsgIDs}{$id})) {
- $DMSGgleich = 0;
- Log3 $name, SDUINO_DISPATCH_VERBOSE, "$name Dispatch: $dmsg, test ungleich";
- }
- else {
- Log3 $name, SDUINO_DISPATCH_VERBOSE, "$name Dispatch: $dmsg, test ungleich: disabled";
- }
- $hash->{LASTDMSG} = $dmsg;
- }
- if ($DMSGgleich) {
- #Dispatch if dispatchequals is provided in protocol definition or only if $dmsg is different from last $dmsg, or if 2 seconds are between transmits
- if ( (SIGNALduino_getProtoProp($id,'dispatchequals',0) eq 'true') || ($hash->{DMSG} ne $dmsg) || ($hash->{TIME}+2 < time() ) ) {
- $hash->{MSGCNT}++;
- $hash->{TIME} = time();
- $hash->{DMSG} = $dmsg;
- #my $event = 0;
- if (substr(ucfirst($dmsg),0,1) eq 'U') {
- #$event = 1;
- DoTrigger($name, "DMSG " . $dmsg);
- }
- #readingsSingleUpdate($hash, "state", $hash->{READINGS}{state}{VAL}, $event);
-
- $hash->{RAWMSG} = $rmsg;
- my %addvals = (DMSG => $dmsg);
- if (AttrVal($name,"suppressDeviceRawmsg",0) == 0) {
- $addvals{RAWMSG} = $rmsg
- }
- if(defined($rssi)) {
- $hash->{RSSI} = $rssi;
- $addvals{RSSI} = $rssi;
- $rssi .= " dB,"
- }
- else {
- $rssi = "";
- }
- Log3 $name, SDUINO_DISPATCH_VERBOSE, "$name Dispatch: $dmsg, $rssi dispatch";
- Dispatch($hash, $dmsg, \%addvals); ## Dispatch to other Modules
-
- } else {
- Log3 $name, 4, "$name Dispatch: $dmsg, Dropped due to short time or equal msg";
- }
- }
- }
- sub
- SIGNALduino_Parse_MS($$$$%)
- {
- my ($hash, $iohash, $name, $rmsg,%msg_parts) = @_;
- my $protocolid;
- my $syncidx=$msg_parts{syncidx};
- my $clockidx=$msg_parts{clockidx};
- my $rawRssi=$msg_parts{rssi};
- my $protocol=undef;
- my $rawData=$msg_parts{rawData};
- my %patternList;
- my $rssi;
- if (defined($rawRssi)) {
- $rssi = ($rawRssi>=128 ? (($rawRssi-256)/2-74) : ($rawRssi/2-74)); # todo: passt dies so? habe ich vom 00_cul.pm
- }
- #$patternList{$_} = $msg_parts{rawData}{$_] for keys %msg_parts{rawData};
- #$patternList = \%msg_parts{pattern};
- #Debug "Message splitted:";
- #Debug Dumper(\@msg_parts);
- my $debug = AttrVal($iohash->{NAME},"debug",0);
-
- if (defined($clockidx) and defined($syncidx))
- {
-
- ## Make a lookup table for our pattern index ids
- #Debug "List of pattern:";
- my $clockabs= $msg_parts{pattern}{$msg_parts{clockidx}};
- return undef if ($clockabs == 0);
- $patternList{$_} = round($msg_parts{pattern}{$_}/$clockabs,1) for keys %{$msg_parts{pattern}};
-
-
- #Debug Dumper(\%patternList);
- #my $syncfact = $patternList{$syncidx}/$patternList{$clockidx};
- #$syncfact=$patternList{$syncidx};
- #Debug "SF=$syncfact";
- #### Convert rawData in Message
- my $signal_length = length($rawData); # Length of data array
- ## Iterate over the data_array and find zero, one, float and sync bits with the signalpattern
- ## Find matching protocols
- my $id;
- my $message_dispatched=0;
- foreach $id (@{$hash->{msIdList}}) {
-
- my $valid=1;
- #$debug=1;
- Debug "Testing against Protocol id $id -> $ProtocolListSIGNALduino{$id}{name}" if ($debug);
- # Check Clock if is it in range
- $valid=SIGNALduino_inTol($ProtocolListSIGNALduino{$id}{clockabs},$clockabs,$clockabs*0.30) if ($ProtocolListSIGNALduino{$id}{clockabs} > 0);
- Debug "validclock = $valid" if ($debug);
-
- next if (!$valid) ;
- my $bit_length = ($signal_length-(scalar @{$ProtocolListSIGNALduino{$id}{sync}}))/((scalar @{$ProtocolListSIGNALduino{$id}{one}} + scalar @{$ProtocolListSIGNALduino{$id}{zero}})/2);
- #Check calculated min length
- $valid = $valid && $ProtocolListSIGNALduino{$id}{length_min} <= $bit_length if (exists $ProtocolListSIGNALduino{$id}{length_min});
- #Check calculated max length
- $valid = $valid && $ProtocolListSIGNALduino{$id}{length_max} >= $bit_length if (exists $ProtocolListSIGNALduino{$id}{length_max});
- Debug "expecting $bit_length bits in signal" if ($debug);
- next if (!$valid) ;
- #Debug Dumper(@{$ProtocolListSIGNALduino{$id}{sync}});
- Debug "Searching in patternList: ".Dumper(\%patternList) if($debug);
- Debug "searching sync: @{$ProtocolListSIGNALduino{$id}{sync}}[0] @{$ProtocolListSIGNALduino{$id}{sync}}[1]" if($debug); # z.B. [1, -18]
- #$valid = $valid && SIGNALduino_inTol($patternList{$clockidx}, @{$ProtocolListSIGNALduino{$id}{sync}}[0], 3); #sync in tolerance
- #$valid = $valid && SIGNALduino_inTol($patternList{$syncidx}, @{$ProtocolListSIGNALduino{$id}{sync}}[1], 3); #sync in tolerance
-
- my $pstr;
- my %patternLookupHash=();
- $valid = $valid && ($pstr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{sync}},\%patternList,\$rawData)) >=0;
- Debug "Found matched sync with indexes: ($pstr)" if ($debug && $valid);
- $patternLookupHash{$pstr}="" if ($valid); ## Append Sync to our lookuptable
- my $syncstr=$pstr; # Store for later start search
- Debug "sync not found " if (!$valid && $debug); # z.B. [1, -18]
- next if (!$valid) ;
- $valid = $valid && ($pstr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{one}},\%patternList,\$rawData)) >=0;
- Debug "Found matched one with indexes: ($pstr)" if ($debug && $valid);
- $patternLookupHash{$pstr}="1" if ($valid); ## Append Sync to our lookuptable
- #Debug "added $pstr " if ($debug && $valid);
- Debug "one pattern not found" if ($debug && !$valid);
- $valid = $valid && ($pstr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{zero}},\%patternList,\$rawData)) >=0;
- Debug "Found matched zero with indexes: ($pstr)" if ($debug && $valid);
- $patternLookupHash{$pstr}="0" if ($valid); ## Append Sync to our lookuptable
- Debug "zero pattern not found" if ($debug && !$valid);
- #Debug "added $pstr " if ($debug && $valid);
- next if (!$valid) ;
- #Debug "Pattern Lookup Table".Dumper(%patternLookupHash);
- ## Check somethin else
-
- #Anything seems to be valid, we can start decoding this.
- Log3 $name, 4, "$name: Matched MS Protocol id $id -> $ProtocolListSIGNALduino{$id}{name}" if ($valid);
- my $signal_width= @{$ProtocolListSIGNALduino{$id}{one}};
- #Debug $signal_width;
-
-
- my @bit_msg; # array to store decoded signal bits
- #for (my $i=index($rawData,SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{sync}}))+$signal_width;$i<length($rawData);$i+=$signal_width)
- #for (my $i=scalar@{$ProtocolListSIGNALduino{$id}{sync}};$i<length($rawData);$i+=$signal_width)
- my $message_start =index($rawData,$syncstr)+length($syncstr);
- Log3 $name, 5, "$name: Starting demodulation at Position $message_start";
-
- for (my $i=$message_start;$i<length($rawData);$i+=$signal_width)
- {
- my $sig_str= substr($rawData,$i,$signal_width);
- #Log3 $name, 5, "demodulating $sig_str";
- #Debug $patternLookupHash{substr($rawData,$i,$signal_width)}; ## Get $signal_width number of chars from raw data string
- if (exists $patternLookupHash{$sig_str}) { ## Add the bits to our bit array
- push(@bit_msg,$patternLookupHash{$sig_str})
- } else {
- Log3 $name, 5, "$name: Found wrong signalpattern, catched ".scalar @bit_msg." bits, aborting demodulation";
- last;
- }
- }
-
-
- Debug "$name: decoded message raw (@bit_msg), ".@bit_msg." bits\n" if ($debug);;
-
- my ($rcode,@retvalue) = SIGNALduino_callsub('postDemodulation',$ProtocolListSIGNALduino{$id}{postDemodulation},$name,@bit_msg);
- next if ($rcode < 1 );
- #Log3 $name, 5, "$name: postdemodulation value @retvalue";
-
- @bit_msg = @retvalue;
- undef(@retvalue); undef($rcode);
- my $padwith = defined($ProtocolListSIGNALduino{$id}{paddingbits}) ? $ProtocolListSIGNALduino{$id}{paddingbits} : 4;
-
- my $i=0;
- while (scalar @bit_msg % $padwith > 0) ## will pad up full nibbles per default or full byte if specified in protocol
- {
- push(@bit_msg,'0');
- $i++;
- }
- Debug "$name padded $i bits to bit_msg array" if ($debug);
-
- #my $logmsg = SIGNALduino_padbits(@bit_msg,$padwith);
-
- #Check converted message against lengths
- $valid = $valid && $ProtocolListSIGNALduino{$id}{length_min} <= scalar @bit_msg if (defined($ProtocolListSIGNALduino{$id}{length_min}));
- $valid = $valid && $ProtocolListSIGNALduino{$id}{length_max} >= scalar @bit_msg if (defined($ProtocolListSIGNALduino{$id}{length_max}));
- next if (!$valid);
-
- #my $dmsg = sprintf "%02x", oct "0b" . join "", @bit_msg; ## Array -> String -> bin -> hex
- my $dmsg = SIGNALduino_b2h(join "", @bit_msg);
- my $postamble = $ProtocolListSIGNALduino{$id}{postamble};
- #if (defined($rawRssi)) {
- #if (defined($ProtocolListSIGNALduino{$id}{preamble}) && $ProtocolListSIGNALduino{$id}{preamble} eq "s") {
- # $postamble = sprintf("%02X", $rawRssi);
- #} elsif ($id eq "7") {
- # $postamble = "#R" . sprintf("%02X", $rawRssi);
- #}
- #}
- $dmsg = "$dmsg".$postamble if (defined($postamble));
- $dmsg = "$ProtocolListSIGNALduino{$id}{preamble}"."$dmsg" if (defined($ProtocolListSIGNALduino{$id}{preamble}));
-
- if (defined($rssi)) {
- Log3 $name, 4, "$name: Decoded MS Protocol id $id dmsg $dmsg length " . scalar @bit_msg . " RSSI = $rssi";
- } else {
- Log3 $name, 4, "$name: Decoded MS Protocol id $id dmsg $dmsg length " . scalar @bit_msg;
- }
-
- #my ($rcode,@retvalue) = SIGNALduino_callsub('preDispatchfunc',$ProtocolListSIGNALduino{$id}{preDispatchfunc},$name,$dmsg);
- #next if (!$rcode);
- #$dmsg = @retvalue;
- #undef(@retvalue); undef($rcode);
-
- my $modulematch = undef;
- if (defined($ProtocolListSIGNALduino{$id}{modulematch})) {
- $modulematch = $ProtocolListSIGNALduino{$id}{modulematch};
- }
- if (!defined($modulematch) || $dmsg =~ m/$modulematch/) {
- Debug "$name: dispatching now msg: $dmsg" if ($debug);
- if (defined($ProtocolListSIGNALduino{$id}{developId}) && substr($ProtocolListSIGNALduino{$id}{developId},0,1) eq "m") {
- my $devid = "m$id";
- my $develop = lc(AttrVal($name,"development",""));
- if ($develop !~ m/$devid/) { # kein dispatch wenn die Id nicht im Attribut development steht
- Log3 $name, 3, "$name: ID=$devid skiped dispatch (developId=m). To use, please add m$id to the attr development";
- next;
- }
- }
- SIGNALduno_Dispatch($hash,$rmsg,$dmsg,$rssi,$id);
- $message_dispatched=1;
- }
- }
-
- return 0 if (!$message_dispatched);
-
- return 1;
-
- }
- }
- ## //Todo: check list as reference
- sub SIGNALduino_padbits(\@$)
- {
- my $i=@{$_[0]} % $_[1];
- while (@{$_[0]} % $_[1] > 0) ## will pad up full nibbles per default or full byte if specified in protocol
- {
- push(@{$_[0]},'0');
- }
- return " padded $i bits to bit_msg array";
- }
- # - - - - - - - - - - - -
- #=item SIGNALduino_getProtoProp()
- #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
- #
- # returns "" if the var is not defined
- # =cut
- # $id, $propertyname,
- sub SIGNALduino_getProtoProp
- {
- my ($id,$propNameLst,$default) = @_;
-
- #my $id = shift;
- #my $propNameLst = shift;
- return $ProtocolListSIGNALduino{$id}{$propNameLst} if defined($ProtocolListSIGNALduino{$id}{$propNameLst});
- return $default; # Will return undef if $default is not provided
- #return undef;
- }
- sub SIGNALduino_Parse_MU($$$$@)
- {
- my ($hash, $iohash, $name, $rmsg,%msg_parts) = @_;
- my $protocolid;
- my $clockidx=$msg_parts{clockidx};
- my $rssi=$msg_parts{rssi};
- my $protocol=undef;
- my $rawData;
- my %patternListRaw;
- my $message_dispatched=0;
- my $debug = AttrVal($iohash->{NAME},"debug",0);
-
- if (defined($rssi)) {
- $rssi = ($rssi>=128 ? (($rssi-256)/2-74) : ($rssi/2-74)); # todo: passt dies so? habe ich vom 00_cul.pm
- }
-
- Debug "$name: processing unsynced message\n" if ($debug);
- my $clockabs = 1; #Clock will be fetched from Protocol if possible
- #$patternListRaw{$_} = floor($msg_parts{pattern}{$_}/$clockabs) for keys $msg_parts{pattern};
- $patternListRaw{$_} = $msg_parts{pattern}{$_} for keys %{$msg_parts{pattern}};
-
- if (defined($clockidx))
- {
-
- ## Make a lookup table for our pattern index ids
- #Debug "List of pattern:"; #Debug Dumper(\%patternList);
- ## Find matching protocols
- my $id;
- foreach $id (@{$hash->{muIdList}}) {
-
- my $valid=1;
- $clockabs= $ProtocolListSIGNALduino{$id}{clockabs};
- my %patternList;
- $rawData=$msg_parts{rawData};
- if (exists($ProtocolListSIGNALduino{$id}{filterfunc}))
- {
- my $method = $ProtocolListSIGNALduino{$id}{filterfunc};
- if (!exists &$method)
- {
- Log3 $name, 5, "$name: Error: Unknown filtermethod=$method. Please define it in file $0";
- next;
- } else {
- Log3 $name, 5, "$name: applying filterfunc $method";
- no strict "refs";
- (my $count_changes,$rawData,my %patternListRaw_tmp) = $method->($name,$id,$rawData,%patternListRaw);
- use strict "refs";
- %patternList = map { $_ => round($patternListRaw_tmp{$_}/$clockabs,1) } keys %patternListRaw_tmp;
- }
- } else {
- %patternList = map { $_ => round($patternListRaw{$_}/$clockabs,1) } keys %patternListRaw;
- }
-
- my $signal_length = length($rawData); # Length of data array
-
- my @keys = sort { $patternList{$a} <=> $patternList{$b} } keys %patternList;
- #Debug Dumper(\%patternList);
- #Debug Dumper(@keys);
- #$debug=1;
-
- Debug "Testing against Protocol id $id -> $ProtocolListSIGNALduino{$id}{name}" if ($debug);
-
- # $valid=SIGNALduino_inTol($ProtocolListSIGNALduino{$id}{clockabs},$clockabs,$clockabs*0.30) if ($ProtocolListSIGNALduino{$id}{clockabs} > 0);
- next if (!$valid) ;
-
- my $bit_length = ($signal_length/((scalar @{$ProtocolListSIGNALduino{$id}{one}} + scalar @{$ProtocolListSIGNALduino{$id}{zero}})/2));
- Debug "Expect $bit_length bits in message" if ($valid && $debug);
- #Check calculated min length
- #$valid = $valid && $ProtocolListSIGNALduino{$id}{length_min} <= $bit_length if (exists $ProtocolListSIGNALduino{$id}{length_min});
- #Check calculated max length
- #$valid = $valid && $ProtocolListSIGNALduino{$id}{length_max} >= $bit_length if (exists $ProtocolListSIGNALduino{$id}{length_max});
- #next if (!$valid) ;
- #Debug "expecting $bit_length bits in signal" if ($debug && $valid);
- Debug "Searching in patternList: ".Dumper(\%patternList) if($debug);
- next if (!$valid) ;
-
- my %patternLookupHash=();
- #Debug "phash:".Dumper(%patternLookupHash);
- my $pstr="";
- $valid = $valid && ($pstr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{one}},\%patternList,\$rawData)) >=0;
- Debug "Found matched one" if ($debug && $valid);
- my $oneStr=$pstr if ($valid);
- $patternLookupHash{$pstr}="1" if ($valid); ## Append one to our lookuptable
- Debug "added $pstr " if ($debug && $valid);
- my $zeroStr ="";
- if (scalar @{$ProtocolListSIGNALduino{$id}{zero}} >0) {
- $valid = $valid && ($pstr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{zero}},\%patternList,\$rawData)) >=0;
- Debug "Found matched zero" if ($debug && $valid);
- $zeroStr=$pstr if ($valid);
- $patternLookupHash{$pstr}="0" if ($valid); ## Append zero to our lookuptable
- Debug "added $pstr " if ($debug && $valid);
- }
- if (defined($ProtocolListSIGNALduino{$id}{float}))
- {
- $valid = $valid && ($pstr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{float}},\%patternList,\$rawData)) >=0;
- Debug "Found matched float" if ($debug && $valid);
- $patternLookupHash{$pstr}="F" if ($valid); ## Append float to our lookuptable
- Debug "added $pstr " if ($debug && $valid);
- }
- next if (!$valid) ;
- #Debug "Pattern Lookup Table".Dumper(%patternLookupHash);
- ## Check somethin else
-
- #Anything seems to be valid, we can start decoding this.
- Log3 $name, 4, "$name: Fingerprint for MU Protocol id $id -> $ProtocolListSIGNALduino{$id}{name} matches, trying to demodulate" if ($valid);
- my $signal_width= @{$ProtocolListSIGNALduino{$id}{one}};
- #Debug $signal_width;
-
- my @bit_msg=(); # array to store decoded signal bits
-
- my $message_start=0 ;
- my @msgStartLst;
- my $startStr="";
- my $start_regex;
- #my $oneStr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{one}},\%patternList,\$rawData);
- #my $zeroStr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{zero}},\%patternList,\$rawData);
- if (@msgStartLst = SIGNALduino_getProtoProp($id,"start"))
- {
- Debug "msgStartLst: ".Dumper(@msgStartLst) if ($debug);
-
- if ( ($startStr=SIGNALduino_PatternExists($hash,@msgStartLst,\%patternList,\$rawData)) eq -1)
- {
- Log3 $name, 5, "$name: start pattern for MU Protocol id $id -> $ProtocolListSIGNALduino{$id}{name} mismatches, aborting" ;
- $valid=0;
- next;
- };
- }
-
-
- if (length ($zeroStr) > 0 ){ $start_regex = "$startStr\($oneStr\|$zeroStr\)";}
- else {$start_regex = $startStr.$oneStr; }
-
- Debug "Regex is: $start_regex" if ($debug);
- $rawData =~ /$start_regex/;
- if (defined($-[0] && $-[0] > 0)) {
- $message_start=$-[0]+ length($startStr);
- } else {
- undef($message_start);
- }
- undef @msgStartLst;
-
- #for (my $i=index($rawData,SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{sync}}))+$signal_width;$i<length($rawData);$i+=$signal_width)
- Debug "Message starts at $message_start - length of data is ".length($rawData) if ($debug);
- next if (!defined($message_start));
- Log3 $name, 5, "$name: Starting demodulation at Position $message_start";
- #my $onepos= index($rawData,SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{one}},\%patternList));
- #my $zeropos=index($rawData,SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{zero}},\%patternList));
- #Log3 $name, 3, "op=$onepos zp=$zeropos";
- #Debug "phash:".Dumper(%patternLookupHash);
-
- my $padwith = defined($ProtocolListSIGNALduino{$id}{paddingbits}) ? $ProtocolListSIGNALduino{$id}{paddingbits} : 4;
-
- for (my $i=$message_start;$i<=length($rawData)-$signal_width;$i+=$signal_width)
- {
-
- my $sig_str= substr($rawData,$i,$signal_width);
- Debug "$name: i=$i search=$sig_str" if ($debug);
- $valid=1; # Set valid to 1 for every loop
- #Debug $patternLookupHash{substr($rawData,$i,$signal_width)}; ## Get $signal_width number of chars from raw data string
- if (exists $patternLookupHash{$sig_str})
- {
- my $bit = $patternLookupHash{$sig_str};
-
- push(@bit_msg,$bit) if (looks_like_number($bit)) ; ## Add the bits to our bit array
- }
- if (!exists $patternLookupHash{$sig_str} || $i+$signal_width>length($rawData)-$signal_width) ## Dispatch if last signal or unknown data
- {
- Debug "$name: demodulated message raw (@bit_msg), ".@bit_msg." bits\n" if ($debug);
- #Check converted message against lengths
- $valid = $valid && $ProtocolListSIGNALduino{$id}{length_max} >= scalar @bit_msg if (defined($ProtocolListSIGNALduino{$id}{length_max}));
- $valid = $valid && $ProtocolListSIGNALduino{$id}{length_min} <= scalar @bit_msg if (defined($ProtocolListSIGNALduino{$id}{length_min}));
-
- #next if (!$valid); ## Last chance to try next protocol if there is somethin invalid
- if ($valid) {
-
- my ($rcode,@retvalue) = SIGNALduino_callsub('postDemodulation',$ProtocolListSIGNALduino{$id}{postDemodulation},$name,@bit_msg);
- next if ($rcode < 1 );
- #Log3 $name, 5, "$name: postdemodulation value @retvalue";
-
- @bit_msg = @retvalue;
- undef(@retvalue); undef($rcode);
-
-
- while (scalar @bit_msg % $padwith > 0) ## will pad up full nibbles per default or full byte if specified in protocol
- {
- push(@bit_msg,'0');
- Debug "$name: padding 0 bit to bit_msg array" if ($debug);
- }
-
- Log3 $name, 5, "$name: dispatching bits: @bit_msg";
- my $dmsg = SIGNALduino_b2h(join "", @bit_msg);
- $dmsg =~ s/^0+// if (defined($ProtocolListSIGNALduino{$id}{remove_zero}));
- $dmsg = "$dmsg"."$ProtocolListSIGNALduino{$id}{postamble}" if (defined($ProtocolListSIGNALduino{$id}{postamble}));
- $dmsg = "$ProtocolListSIGNALduino{$id}{preamble}"."$dmsg" if (defined($ProtocolListSIGNALduino{$id}{preamble}));
-
- if (defined($rssi)) {
- Log3 $name, 4, "$name: decoded matched MU Protocol id $id dmsg $dmsg length " . scalar @bit_msg . " RSSI = $rssi";
- } else {
- Log3 $name, 4, "$name: decoded matched MU Protocol id $id dmsg $dmsg length " . scalar @bit_msg;
- }
-
- my $modulematch;
- if (defined($ProtocolListSIGNALduino{$id}{modulematch})) {
- $modulematch = $ProtocolListSIGNALduino{$id}{modulematch};
- }
- if (!defined($modulematch) || $dmsg =~ m/$modulematch/) {
- Debug "$name: dispatching now msg: $dmsg" if ($debug);
- if (defined($ProtocolListSIGNALduino{$id}{developId}) && substr($ProtocolListSIGNALduino{$id}{developId},0,1) eq "m") {
- my $devid = "m$id";
- my $develop = lc(AttrVal($name,"development",""));
- if ($develop !~ m/$devid/) { # kein dispatch wenn die Id nicht im Attribut development steht
- Log3 $name, 3, "$name: ID=$devid skiped dispatch (developId=m). To use, please add m$id to the attr development";
- next;
- }
- }
-
- SIGNALduno_Dispatch($hash,$rmsg,$dmsg,$rssi,$id);
- $message_dispatched=1;
- }
- } else {
- if ($debug)
- {
- my $debugstr;
- $debugstr.=$ProtocolListSIGNALduino{$id}{length_min} if defined($ProtocolListSIGNALduino{$id}{length_min});
- $debugstr.="/";
- $debugstr.=$ProtocolListSIGNALduino{$id}{length_max} if defined($ProtocolListSIGNALduino{$id}{length_max});
-
- Debug "$name: length ($debugstr) does not match (@bit_msg), ".@bit_msg." bits\n";
- }
-
- }
- @bit_msg=(); # clear bit_msg array
-
- #Find next position of valid signal (skip invalid pieces)
- my $regex=".{$i}".$start_regex;
- Debug "$name: searching new start with ($regex)\n" if ($debug);
-
- $rawData =~ /$regex/;
- if (defined($-[0]) && ($-[0] > 0)) {
- #$i=$-[0]+ $i+ length($startStr);
- $i=$-[0]+ $i;
- $i=$i-$signal_width if ($i>0 && length($startStr) == 0); #Todo:
- Debug "$name: found restart at Position $i ($regex)\n" if ($debug);
- } else {
- last;
- }
-
- #if ($startStr)
- #{
- # $i= index($rawData,$startStr,$i);
- # } else {
- # $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));
- # $i-=$signal_width if ($i<length($rawData)-$signal_width) ;
- #
- # }
- # last if ($i <=-1);
- Log3 $name, 5, "$name: restarting demodulation at Position $i+$signal_width" if ($debug);
-
- }
- }
-
- #my $dmsg = sprintf "%02x", oct "0b" . join "", @bit_msg; ## Array -> String -> bin -> hex
- }
- return 0 if (!$message_dispatched);
-
- return 1;
- }
- }
- sub
- SIGNALduino_Parse_MC($$$$@)
- {
- my ($hash, $iohash, $name, $rmsg,%msg_parts) = @_;
- my $clock=$msg_parts{clockabs}; ## absolute clock
- my $rawData=$msg_parts{rawData};
- my $rssi=$msg_parts{rssi};
- my $mcbitnum=$msg_parts{mcbitnum};
- my $bitData;
- my $dmsg;
- my $message_dispatched=0;
- my $debug = AttrVal($iohash->{NAME},"debug",0);
- if (defined($rssi)) {
- $rssi = ($rssi>=128 ? (($rssi-256)/2-74) : ($rssi/2-74)); # todo: passt dies so? habe ich vom 00_cul.pm
- }
-
- return undef if (!$clock);
- #my $protocol=undef;
- #my %patternListRaw = %msg_parts{patternList};
-
- Debug "$name: processing manchester messag len:".length($rawData) if ($debug);
-
- my $hlen = length($rawData);
- my $blen;
- #if (defined($mcbitnum)) {
- # $blen = $mcbitnum;
- #} else {
- $blen = $hlen * 4;
- #}
- my $id;
-
- my $rawDataInverted;
- ($rawDataInverted = $rawData) =~ tr/0123456789ABCDEF/FEDCBA9876543210/; # Some Manchester Data is inverted
-
- foreach $id (@{$hash->{mcIdList}}) {
- #next if ($blen < $ProtocolListSIGNALduino{$id}{length_min} || $blen > $ProtocolListSIGNALduino{$id}{length_max});
- #if ( $clock >$ProtocolListSIGNALduino{$id}{clockrange}[0] and $clock <$ProtocolListSIGNALduino{$id}{clockrange}[1]);
- if ( $clock >$ProtocolListSIGNALduino{$id}{clockrange}[0] and $clock <$ProtocolListSIGNALduino{$id}{clockrange}[1] and length($rawData)*4 >= $ProtocolListSIGNALduino{$id}{length_min} )
- {
- Debug "clock and min length matched" if ($debug);
- if (defined($rssi)) {
- Log3 $name, 4, "$name: Found manchester Protocol id $id clock $clock RSSI $rssi -> $ProtocolListSIGNALduino{$id}{name}";
- } else {
- Log3 $name, 4, "$name: Found manchester Protocol id $id clock $clock -> $ProtocolListSIGNALduino{$id}{name}";
- }
-
- if (exists($ProtocolListSIGNALduino{$id}{polarity}) && ($ProtocolListSIGNALduino{$id}{polarity} eq 'invert') && (!defined($hash->{version}) || substr($hash->{version},0,6) ne 'V 3.2.'))
- # todo && substr($hash->{version},0,6) ne 'V 3.2.') # bei version V 3.2. nicht invertieren
- {
- $bitData= unpack("B$blen", pack("H$hlen", $rawDataInverted));
- } else {
- $bitData= unpack("B$blen", pack("H$hlen", $rawData));
- }
- Debug "$name: extracted data $bitData (bin)\n" if ($debug); ## Convert Message from hex to bits
- Log3 $name, 5, "$name: extracted data $bitData (bin)";
-
- my $method = $ProtocolListSIGNALduino{$id}{method};
- if (!exists &$method)
- {
- Log3 $name, 5, "$name: Error: Unknown function=$method. Please define it in file $0";
- } else {
- my ($rcode,$res) = $method->($name,$bitData,$id,$mcbitnum);
- if ($rcode != -1) {
- $dmsg = $res;
- $dmsg=$ProtocolListSIGNALduino{$id}{preamble}.$dmsg if (defined($ProtocolListSIGNALduino{$id}{preamble}));
- my $modulematch;
- if (defined($ProtocolListSIGNALduino{$id}{modulematch})) {
- $modulematch = $ProtocolListSIGNALduino{$id}{modulematch};
- }
- if (!defined($modulematch) || $dmsg =~ m/$modulematch/) {
- if (defined($ProtocolListSIGNALduino{$id}{developId}) && substr($ProtocolListSIGNALduino{$id}{developId},0,1) eq "m") {
- my $devid = "m$id";
- my $develop = lc(AttrVal($name,"development",""));
- if ($develop !~ m/$devid/) { # kein dispatch wenn die Id nicht im Attribut development steht
- Log3 $name, 3, "$name: ID=$devid skiped dispatch (developId=m). To use, please add m$id to the attr development";
- next;
- }
- }
- SIGNALduno_Dispatch($hash,$rmsg,$dmsg,$rssi,$id);
- $message_dispatched=1;
- }
- } else {
- $res="undef" if (!defined($res));
- Log3 $name, 5, "$name: protocol does not match return from method: ($res)" ;
- }
- }
- }
-
- }
- return 0 if (!$message_dispatched);
- return 1;
- }
- sub
- SIGNALduino_Parse($$$$@)
- {
- my ($hash, $iohash, $name, $rmsg, $initstr) = @_;
- #print Dumper(\%ProtocolListSIGNALduino);
-
-
- if (!($rmsg=~ s/^\002(M.;.*;)\003/$1/)) # Check if a Data Message arrived and if it's complete (start & end control char are received)
- { # cut off start end end character from message for further processing they are not needed
- Log3 $name, AttrVal($name,"noMsgVerbose",5), "$name/noMsg Parse: $rmsg";
- return undef;
- }
- if (defined($hash->{keepalive})) {
- $hash->{keepalive}{ok} = 1;
- $hash->{keepalive}{retry} = 0;
- }
-
- my $debug = AttrVal($iohash->{NAME},"debug",0);
-
-
- Debug "$name: incomming message: ($rmsg)\n" if ($debug);
-
- if (AttrVal($name, "rawmsgEvent", 0)) {
- DoTrigger($name, "RAWMSG " . $rmsg);
- }
-
- my %signal_parts=SIGNALduino_Split_Message($rmsg,$name); ## Split message and save anything in an hash %signal_parts
- #Debug "raw data ". $signal_parts{rawData};
-
-
- my $dispatched;
- # Message Synced type -> M#
- if (@{$hash->{msIdList}} && $rmsg=~ m/^MS;(P\d=-?\d+;){3,8}D=\d+;CP=\d;SP=\d;/)
- {
- $dispatched= SIGNALduino_Parse_MS($hash, $iohash, $name, $rmsg,%signal_parts);
- }
- # Message unsynced type -> MU
- elsif (@{$hash->{muIdList}} && $rmsg=~ m/^MU;(P\d=-?\d+;){3,8}D=\d+;CP=\d;/)
- {
- $dispatched= SIGNALduino_Parse_MU($hash, $iohash, $name, $rmsg,%signal_parts);
- }
- # Manchester encoded Data -> MC
- elsif (@{$hash->{mcIdList}} && $rmsg=~ m/^MC;.*;/)
- {
- $dispatched= SIGNALduino_Parse_MC($hash, $iohash, $name, $rmsg,%signal_parts);
- }
- else {
- Debug "$name: unknown Messageformat, aborting\n" if ($debug);
- return undef;
- }
-
- if ( AttrVal($hash->{NAME},"verbose","0") > 4 && !$dispatched)
- {
- my $notdisplist;
- my @lines;
- if (defined($hash->{unknownmessages}))
- {
- $notdisplist=$hash->{unknownmessages};
- @lines = split ('#', $notdisplist); # or whatever
- }
- push(@lines,FmtDateTime(time())."-".$rmsg);
- shift(@lines)if (scalar @lines >25);
- $notdisplist = join('#',@lines);
- $hash->{unknownmessages}=$notdisplist;
- return undef;
- #Todo compare Sync/Clock fact and length of D= if equal, then it's the same protocol!
- }
- }
- #####################################
- sub
- SIGNALduino_Ready($)
- {
- my ($hash) = @_;
- if ($hash->{STATE} eq 'disconnected') {
- $hash->{DevState} = 'disconnected';
- return DevIo_OpenDev($hash, 1, "SIGNALduino_DoInit", 'SIGNALduino_Connect')
- }
-
- # This is relevant for windows/USB only
- my $po = $hash->{USBDev};
- my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags);
- if($po) {
- ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags) = $po->status;
- }
- return ($InBytes && $InBytes>0);
- }
- sub
- SIGNALduino_WriteInit($)
- {
- my ($hash) = @_;
-
- # todo: ist dies so ausreichend, damit die Aenderungen uebernommen werden?
- SIGNALduino_AddSendQueue($hash,"WS36"); # SIDLE, Exit RX / TX, turn off frequency synthesizer
- SIGNALduino_AddSendQueue($hash,"WS34"); # SRX, Enable RX. Perform calibration first if coming from IDLE and MCSM0.FS_AUTOCAL=1.
- }
- ########################
- sub
- SIGNALduino_SimpleWrite(@)
- {
- my ($hash, $msg, $nonl) = @_;
- return if(!$hash);
- if($hash->{TYPE} eq "SIGNALduino_RFR") {
- # Prefix $msg with RRBBU and return the corresponding SIGNALduino hash.
- ($hash, $msg) = SIGNALduino_RFR_AddPrefix($hash, $msg);
- }
- my $name = $hash->{NAME};
- Log3 $name, 5, "$name SW: $msg";
- $msg .= "\n" unless($nonl);
- $hash->{USBDev}->write($msg) if($hash->{USBDev});
- syswrite($hash->{TCPDev}, $msg) if($hash->{TCPDev});
- syswrite($hash->{DIODev}, $msg) if($hash->{DIODev});
- # Some linux installations are broken with 0.001, T01 returns no answer
- select(undef, undef, undef, 0.01);
- }
- sub
- SIGNALduino_Attr(@)
- {
- my ($cmd,$name,$aName,$aVal) = @_;
- my $hash = $defs{$name};
- my $debug = AttrVal($name,"debug",0);
-
- $aVal= "" if (!defined($aVal));
- Log3 $name, 4, "$name: Calling Getting Attr sub with args: $cmd $aName = $aVal";
-
- if( $aName eq "Clients" ) { ## Change clientList
- $hash->{Clients} = $aVal;
- $hash->{Clients} = $clientsSIGNALduino if( !$hash->{Clients}) ; ## Set defaults
- return "Setting defaults";
- } elsif( $aName eq "MatchList" ) { ## Change matchList
- my $match_list;
- if( $cmd eq "set" ) {
- $match_list = eval $aVal;
- if( $@ ) {
- Log3 $name, 2, $name .": $aVal: ". $@;
- }
- }
-
- if( ref($match_list) eq 'HASH' ) {
- $hash->{MatchList} = $match_list;
- } else {
- $hash->{MatchList} = \%matchListSIGNALduino; ## Set defaults
- Log3 $name, 2, $name .": $aVal: not a HASH using defaults" if( $aVal );
- }
- }
- elsif ($aName eq "verbose")
- {
- Log3 $name, 3, "$name: setting Verbose to: " . $aVal;
- $hash->{unknownmessages}="" if $aVal <4;
-
- }
- elsif ($aName eq "debug")
- {
- $debug = $aVal;
- Log3 $name, 3, "$name: setting debug to: " . $debug;
- }
- elsif ($aName eq "whitelist_IDs")
- {
- Log3 $name, 3, "$name Attr: whitelist_IDs";
- if ($init_done) { # beim fhem Start wird das SIGNALduino_IdList nicht aufgerufen, da es beim define aufgerufen wird
- SIGNALduino_IdList("x:$name",$aVal);
- }
- }
- elsif ($aName eq "blacklist_IDs")
- {
- Log3 $name, 3, "$name Attr: blacklist_IDs";
- if ($init_done) { # beim fhem Start wird das SIGNALduino_IdList nicht aufgerufen, da es beim define aufgerufen wird
- SIGNALduino_IdList("x:$name",undef,$aVal);
- }
- }
- elsif ($aName eq "development")
- {
- Log3 $name, 3, "$name Attr: development";
- if ($init_done) { # beim fhem Start wird das SIGNALduino_IdList nicht aufgerufen, da es beim define aufgerufen wird
- SIGNALduino_IdList("x:$name",undef,undef,$aVal);
- }
- }
- elsif ($aName eq "doubleMsgCheck_IDs")
- {
- if (defined($aVal)) {
- if (length($aVal)>0) {
- if (substr($aVal,0 ,1) eq '#') {
- Log3 $name, 3, "$name Attr: doubleMsgCheck_IDs disabled: $aVal";
- delete $hash->{DoubleMsgIDs};
- }
- else {
- Log3 $name, 3, "$name Attr: doubleMsgCheck_IDs enabled: $aVal";
- my %DoubleMsgiD = map { $_ => 1 } split(",", $aVal);
- $hash->{DoubleMsgIDs} = \%DoubleMsgiD;
- #print Dumper $hash->{DoubleMsgIDs};
- }
- }
- else {
- Log3 $name, 3, "$name delete Attr: doubleMsgCheck_IDs";
- delete $hash->{DoubleMsgIDs};
- }
- }
- }
- elsif ($aName eq "cc1101_frequency")
- {
- if ($aVal eq "" || $aVal < 800) {
- Log3 $name, 3, "$name: delete cc1101_frequeny";
- delete ($hash->{cc1101_frequency}) if (defined($hash->{cc1101_frequency}));
- } else {
- Log3 $name, 3, "$name: setting cc1101_frequency to 868";
- $hash->{cc1101_frequency} = 868;
- }
- }
-
- return undef;
- }
- sub SIGNALduino_IdList($@)
- {
- my ($param, $aVal, $blacklist, $develop) = @_;
- my (undef,$name) = split(':', $param);
- my $hash = $defs{$name};
- my @msIdList = ();
- my @muIdList = ();
- my @mcIdList = ();
- if (!defined($aVal)) {
- $aVal = AttrVal($name,"whitelist_IDs","");
- }
- Log3 $name, 3, "$name sduinoIdList: whitelistIds=$aVal";
-
- if (!defined($blacklist)) {
- $blacklist = AttrVal($name,"blacklist_IDs","");
- }
- Log3 $name, 3, "$name sduinoIdList: blacklistIds=$blacklist";
-
- if (!defined($develop)) {
- $develop = AttrVal($name,"development","");
- }
- $develop = lc($develop);
- Log3 $name, 3, "$name sduinoIdList: development=$develop";
- my %WhitelistIDs;
- my %BlacklistIDs;
- my $wflag = 0; # whitelist flag, 0=disabled
- my $bflag = 0; # blacklist flag, 0=disabled
- if (defined($aVal) && length($aVal)>0)
- {
- if (substr($aVal,0 ,1) eq '#') {
- Log3 $name, 3, "$name Attr whitelist disabled: $aVal";
- }
- else {
- %WhitelistIDs = map { $_ => 1 } split(",", $aVal);
- #my $w = join ', ' => map "$_" => keys %WhitelistIDs;
- #Log3 $name, 3, "Attr whitelist $w";
- $wflag = 1;
- }
- }
- if ($wflag == 0) { # whitelist disabled
- if (defined($blacklist) && length($blacklist)>0) {
- %BlacklistIDs = map { $_ => 1 } split(",", $blacklist);
- my $w = join ', ' => map "$_" => keys %BlacklistIDs;
- Log3 $name, 3, "$name Attr blacklist $w";
- $bflag = 1;
- }
- }
-
- my $id;
- foreach $id (keys %ProtocolListSIGNALduino)
- {
- next if ($id eq 'id');
- if ($wflag == 1 && !defined($WhitelistIDs{$id}))
- {
- #Log3 $name, 3, "skip ID $id";
- next;
- }
- if ($bflag == 1 && defined($BlacklistIDs{$id}))
- {
- Log3 $name, 3, "$name skip Blacklist ID $id";
- next;
- }
-
- if (defined($ProtocolListSIGNALduino{$id}{developId}) && substr($ProtocolListSIGNALduino{$id}{developId},0,1) eq "p") {
- my $devid = "p$id";
- if ($develop !~ m/$devid/) { # skip wenn die Id nicht im Attribut development steht
- Log3 $name, 3, "$name: ID=$devid skiped (developId=p)";
- next;
- }
- }
-
- if (defined($ProtocolListSIGNALduino{$id}{developId}) && substr($ProtocolListSIGNALduino{$id}{developId},0,1) eq "y") {
- if ($develop !~ m/y/) { # skip wenn y nicht im Attribut development steht
- Log3 $name, 3, "$name: ID=$id skiped (developId=y)";
- next;
- }
- }
-
- if (exists ($ProtocolListSIGNALduino{$id}{format}) && $ProtocolListSIGNALduino{$id}{format} eq "manchester")
- {
- push (@mcIdList, $id);
- }
- elsif (exists $ProtocolListSIGNALduino{$id}{sync})
- {
- push (@msIdList, $id);
- }
- elsif (exists ($ProtocolListSIGNALduino{$id}{clockabs}))
- {
- push (@muIdList, $id);
- }
- }
- @msIdList = sort @msIdList;
- @muIdList = sort @muIdList;
- @mcIdList = sort @mcIdList;
- Log3 $name, 3, "$name: IDlist MS @msIdList";
- Log3 $name, 3, "$name: IDlist MU @muIdList";
- Log3 $name, 3, "$name: IDlist MC @mcIdList";
-
- $hash->{msIdList} = \@msIdList;
- $hash->{muIdList} = \@muIdList;
- $hash->{mcIdList} = \@mcIdList;
- }
- sub SIGNALduino_callsub
- {
- my $funcname =shift;
- my $method = shift;
- my $name = shift;
- my @args = @_;
-
-
- if ( defined $method && defined &$method )
- {
- #my $subname = @{[eval {&$method}, $@ =~ /.*/]};
- Log3 $name, 5, "$name: applying $funcname"; # method $subname";
- #Log3 $name, 5, "$name: value bevore $funcname: @args";
-
- my ($rcode, @returnvalues) = $method->($name, @args) ;
-
- Log3 $name, 5, "$name: modified value after $funcname: @returnvalues";
- return ($rcode, @returnvalues);
- } elsif (defined $method ) {
- Log3 $name, 5, "$name: Error: Unknown method $funcname Please check definition";
- return (0,undef);
- }
- return (1,@args);
- }
- # calculates the hex (in bits) and adds it at the beginning of the message
- # input = @list
- # output = @list
- sub SIGNALduino_lengtnPrefix
- {
- my ($name, @bit_msg) = @_;
-
- my $msg = join("",@bit_msg);
- #$msg = unpack("B8", pack("N", length($msg))).$msg;
- $msg=sprintf('%08b', length($msg)).$msg;
-
- return (1,split("",$msg));
- }
- sub SIGNALduino_bit2Arctec
- {
- my ($name, @bit_msg) = @_;
- my $msg = join("",@bit_msg);
- # Convert 0 -> 01 1 -> 10 to be compatible with IT Module
- $msg =~ s/0/z/g;
- $msg =~ s/1/10/g;
- $msg =~ s/z/01/g;
- return (1,split("",$msg));
- }
- sub SIGNALduino_ITV1_tristateToBit($)
- {
- my ($msg) = @_;
- # Convert 0 -> 00 1 -> 11 F => 01 to be compatible with IT Module
- $msg =~ s/0/00/g;
- $msg =~ s/1/11/g;
- $msg =~ s/F/01/g;
- $msg =~ s/D/10/g;
-
- return (1,$msg);
- }
- sub SIGNALduino_HE($@) {
- my ($name, @bit_msg) = @_;
- my $msg = join("",@bit_msg);
-
- #Log3 $name, 4, "$name HE: $msg";
- 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);
-
- return (1,split("",$msg));
- }
- sub SIGNALduino_postDemo_Hoermann($@) {
- my ($name, @bit_msg) = @_;
- my $msg = join("",@bit_msg);
-
- if (substr($msg,0,9) ne "000000001") { # check ident
- Log3 $name, 4, "$name: Hoermann ERROR - Ident not 000000001";
- return 0, undef;
- } else {
- Log3 $name, 5, "$name: Hoermann $msg";
- $msg = substr($msg,9);
- return (1,split("",$msg));
- }
- }
- sub SIGNALduino_postDemo_FS20($@) {
- my ($name, @bit_msg) = @_;
- my $datastart = 0;
- my $protolength = scalar @bit_msg;
- my $sum = 0;
- my $b = 0;
- my $i = 0;
- for ($datastart = 0; $datastart < $protolength; $datastart++) { # Start bei erstem Bit mit Wert 1 suchen
- last if $bit_msg[$datastart] eq "1";
- }
- if ($datastart == $protolength) { # all bits are 0
- Log3 $name, 3, "$name: FS20 - ERROR message all bit are zeros";
- return 0, undef;
- }
- splice(@bit_msg, 0, $datastart + 1); # delete preamble + 1 bit
- $protolength = scalar @bit_msg;
-
- if ($protolength == 45) { ### FS20 length 45 or 54
- for(my $b = 0; $b < 36; $b += 9) { # build sum over first 4 bytes
- $sum += oct( "0b".(join "", @bit_msg[$b .. $b + 7]));
- }
- my $checksum = oct( "0b".(join "", @bit_msg[36 .. 43])); # Checksum Byte 5
- if (((($sum + 6) & 0xFF) - $checksum) == 0) { ## FHT80TF Tuer-/Fensterkontakt
- for(my $b = 0; $b < 45; $b += 9) { # check parity over 5 byte
- my $parity = 0; # Parity even
- for(my $i = $b; $i < $b + 9; $i++) { # Parity over 1 byte + 1 bit
- $parity += $bit_msg[$i];
- }
- if ($parity % 2 != 0) {
- Log3 $name, 3, "$name: FS20 ERROR - Parity not even";
- return 0, undef;
- }
- } # parity ok
- for(my $b = 44; $b > 0; $b -= 9) { # delete 5 parity bits
- splice(@bit_msg, $b, 1);
- }
- splice(@bit_msg, 32, 8); # delete checksum
- splice(@bit_msg, 24, 0, (0,0,0,0,0,0,0,0)); # insert Byte 3
- Log3 $name, 4, "$name: FS20 - remote control protolength $protolength";
- return (1, @bit_msg); ## FHT80TF ok
- }
- }
- if ($protolength == 54) { ### FS20 length 45 or 54
- for($b = 0; $b < 45; $b += 9) { # build sum over first 5 bytes
- $sum += oct( "0b".(join "", @bit_msg[$b .. $b + 7]));
- }
- my $checksum = oct( "0b".(join "", @bit_msg[45 .. 52])); # Checksum Byte 6
- if (((($sum + 6) & 0xFF) - $checksum) == 0) { ## FHT80 Raumthermostat
- for($b = 0; $b < 55; $b += 9) { # check parity over 6 byte
- my $parity = 0; # Parity even
- for($i = $b; $i < $b + 9; $i++) { # Parity over 1 byte + 1 bit
- $parity += $bit_msg[$i];
- }
- if ($parity % 2 != 0) {
- Log3 $name, 3, "$name: FHT80 ERROR - Parity not even";
- return 0, undef;
- }
- } # parity ok
- for($b = 53; $b > 0; $b -= 9) { # delete 6 parity bits
- splice(@bit_msg, $b, 1);
- }
- splice(@bit_msg, 40, 8); # delete checksum
- Log3 $name, 4, "$name: FS20 - remote control protolength $protolength";
- return (1, @bit_msg); ## FHT80 ok
- }
- }
- return 0, undef;
- }
- sub SIGNALduino_postDemo_FHT80($@) {
- my ($name, @bit_msg) = @_;
- my $datastart = 0;
- my $protolength = scalar @bit_msg;
- my $sum = 0;
- my $b = 0;
- my $i = 0;
- # if ($protolength < 66) { # min 6 bytes + 6 bits
- # Log3 $name, 3, "$name: FHT80 - ERROR lenght of message < 66";
- # return 0, undef;
- # }
- for ($datastart = 0; $datastart < $protolength; $datastart++) { # Start bei erstem Bit mit Wert 1 suchen
- last if $bit_msg[$datastart] eq "1";
- }
- if ($datastart == $protolength) { # all bits are 0
- Log3 $name, 3, "$name: FHT80 - ERROR message all bit are zeros";
- return 0, undef;
- }
- splice(@bit_msg, 0, $datastart + 1); # delete preamble + 1 bit
- $protolength = scalar @bit_msg;
- if ($protolength == 54) { ### FHT80 fixed length
- for($b = 0; $b < 45; $b += 9) { # build sum over first 5 bytes
- $sum += oct( "0b".(join "", @bit_msg[$b .. $b + 7]));
- }
- my $checksum = oct( "0b".(join "", @bit_msg[45 .. 52])); # Checksum Byte 6
- if (((($sum + 12) & 0xFF) - $checksum) == 0) { ## FHT80 Raumthermostat
- for($b = 0; $b < 55; $b += 9) { # check parity over 6 byte
- my $parity = 0; # Parity even
- for($i = $b; $i < $b + 9; $i++) { # Parity over 1 byte + 1 bit
- $parity += $bit_msg[$i];
- }
- if ($parity % 2 != 0) {
- Log3 $name, 3, "$name: FHT80 ERROR - Parity not even";
- return 0, undef;
- }
- } # parity ok
- for($b = 53; $b > 0; $b -= 9) { # delete 6 parity bits
- splice(@bit_msg, $b, 1);
- }
- if ($bit_msg[26] != 1) { # Bit 5 Byte 3 must 1
- Log3 $name, 3, "$name: FHT80 ERROR - byte 3 bit 5 not 1";
- return 0, undef;
- }
- splice(@bit_msg, 40, 8); # delete checksum
- splice(@bit_msg, 24, 0, (0,0,0,0,0,0,0,0)); # insert Byte 3
- Log3 $name, 4, "$name: FHT80 - roomthermostat protolength $protolength";
- return (1, @bit_msg); ## FHT80 ok
- }
- }
- return 0, undef;
- }
- sub SIGNALduino_postDemo_FHT80TF($@) {
- my ($name, @bit_msg) = @_;
- my $datastart = 0;
- my $protolength = scalar @bit_msg;
- my $sum = 0;
- my $b = 0;
- if ($protolength < 46) { # min 5 bytes + 6 bits
- Log3 $name, 4, "$name: FHT80TF or FS20 - ERROR lenght of message < 46";
- return 0, undef;
- }
- for ($datastart = 0; $datastart < $protolength; $datastart++) { # Start bei erstem Bit mit Wert 1 suchen
- last if $bit_msg[$datastart] eq "1";
- }
- if ($datastart == $protolength) { # all bits are 0
- Log3 $name, 3, "$name: FHTTF or FS20 - ERROR message all bit are zeros";
- return 0, undef;
- }
- splice(@bit_msg, 0, $datastart + 1); # delete preamble + 1 bit
- $protolength = scalar @bit_msg;
- if ($protolength == 45) { ### FHT80TF fixed length
- for(my $b = 0; $b < 36; $b += 9) { # build sum over first 4 bytes
- $sum += oct( "0b".(join "", @bit_msg[$b .. $b + 7]));
- }
- my $checksum = oct( "0b".(join "", @bit_msg[36 .. 43])); # Checksum Byte 5
- if (((($sum + 12) & 0xFF) - $checksum) == 0) { ## FHT80TF Tuer-/Fensterkontakt
- for(my $b = 0; $b < 45; $b += 9) { # check parity over 5 byte
- my $parity = 0; # Parity even
- for(my $i = $b; $i < $b + 9; $i++) { # Parity over 1 byte + 1 bit
- $parity += $bit_msg[$i];
- }
- if ($parity % 2 != 0) {
- Log3 $name, 4, "$name: FHT80TF ERROR - Parity not even";
- return 0, undef;
- }
- } # parity ok
- for(my $b = 44; $b > 0; $b -= 9) { # delete 5 parity bits
- splice(@bit_msg, $b, 1);
- }
- if ($bit_msg[26] != 0) { # Bit 5 Byte 3 must 0
- Log3 $name, 3, "$name: FHT80 ERROR - byte 3 bit 5 not 0";
- return 0, undef;
- }
- splice(@bit_msg, 32, 8); # delete checksum
- Log3 $name, 4, "$name: FHT80TF - door/window switch protolength $protolength";
- return (1, @bit_msg); ## FHT80TF ok
- }
- }
- return 0, undef;
- }
- sub SIGNALduino_postDemo_WS7035($@) {
- my ($name, @bit_msg) = @_;
- my $msg = join("",@bit_msg);
- my $parity = 0; # Parity even
- Log3 $name, 4, "$name: WS7035 $msg";
- if (substr($msg,0,8) ne "10100000") { # check ident
- Log3 $name, 3, "$name: WS7035 ERROR - Ident not 1010 0000";
- return 0, undef;
- } else {
- for(my $i = 15; $i < 28; $i++) { # Parity over bit 15 and 12 bit temperature
- $parity += substr($msg, $i, 1);
- }
- if ($parity % 2 != 0) {
- Log3 $name, 3, "$name: WS7035 ERROR - Parity not even";
- return 0, undef;
- } else {
- 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);
- substr($msg, 27, 4, ''); # delete nibble 8
- return (1,split("",$msg));
- }
- }
- }
- sub SIGNALduino_postDemo_WS2000($@) {
- my ($name, @bit_msg) = @_;
- my $debug = AttrVal($name,"debug",0);
- my @new_bit_msg = "";
- my $protolength = scalar @bit_msg;
- my @datalenghtws = (35,50,35,50,70,40,40,85);
- my $datastart = 0;
- my $datalength = 0;
- my $datalength1 = 0;
- my $index = 0;
- my $data = 0;
- my $dataindex = 0;
- my $error = 0;
- my $check = 0;
- my $sum = 5;
- my $typ = 0;
- my $adr = 0;
- my @sensors = (
- "Thermo",
- "Thermo/Hygro",
- "Rain",
- "Wind",
- "Thermo/Hygro/Baro",
- "Brightness",
- "Pyrano",
- "Kombi"
- );
- for ($datastart = 0; $datastart < $protolength; $datastart++) { # Start bei erstem Bit mit Wert 1 suchen
- last if $bit_msg[$datastart] eq "1";
- }
- if ($datastart == $protolength) { # all bits are 0
- Log3 $name, 3, "$name: WS2000 - ERROR message all bit are zeros";
- return 0, undef;
- }
- $datalength = $protolength - $datastart;
- $datalength1 = $datalength - ($datalength % 5); # modulo 5
- Log3 $name, 5, "$name: WS2000 protolength: $protolength, datastart: $datastart, datalength $datalength";
- $typ = oct( "0b".(join "", reverse @bit_msg[$datastart + 1.. $datastart + 4])); # Sensortyp
- if ($typ > 7) {
- Log3 $name, 4, "$name: WS2000 Sensortyp $typ - ERROR typ to big";
- return 0, undef;
- }
- if ($typ == 1 && ($datalength == 45 || $datalength == 46)) {$datalength1 += 5;} # Typ 1 ohne Summe
- if ($datalenghtws[$typ] != $datalength1) { # check lenght of message
- Log3 $name, 4, "$name: WS2000 Sensortyp $typ - ERROR lenght of message $datalength1 ($datalenghtws[$typ])";
- return 0, undef;
- } elsif ($datastart > 10) { # max 10 Bit preamble
- Log3 $name, 4, "$name: WS2000 ERROR preamble > 10 ($datastart)";
- return 0, undef;
- } else {
- do {
- $error += !$bit_msg[$index + $datastart]; # jedes 5. Bit muss 1 sein
- $dataindex = $index + $datastart + 1;
- $data = oct( "0b".(join "", reverse @bit_msg[$dataindex .. $dataindex + 3]));
- if ($index == 5) {$adr = ($data & 0x07)} # Sensoradresse
- if ($datalength == 45 || $datalength == 46) { # Typ 1 ohne Summe
- if ($index <= $datalength - 5) {
- $check = $check ^ $data; # Check - Typ XOR Adresse XOR bis XOR Check muss 0 ergeben
- }
- } else {
- if ($index <= $datalength - 10) {
- $check = $check ^ $data; # Check - Typ XOR Adresse XOR bis XOR Check muss 0 ergeben
- $sum += $data;
- }
- }
- $index += 5;
- } until ($index >= $datalength);
- }
- if ($error != 0) {
- Log3 $name, 4, "$name: WS2000 Sensortyp $typ Adr $adr - ERROR examination bit";
- return (0, undef);
- } elsif ($check != 0) {
- Log3 $name, 4, "$name: WS2000 Sensortyp $typ Adr $adr - ERROR check XOR";
- return (0, undef);
- } else {
- if ($datalength < 45 || $datalength > 46) { # Summe prüfen, außer Typ 1 ohne Summe
- $data = oct( "0b".(join "", reverse @bit_msg[$dataindex .. $dataindex + 3]));
- if ($data != ($sum & 0x0F)) {
- Log3 $name, 4, "$name: WS2000 Sensortyp $typ Adr $adr - ERROR sum";
- return (0, undef);
- }
- }
- Log3 $name, 4, "$name: WS2000 Sensortyp $typ Adr $adr - $sensors[$typ]";
- $datastart += 1; # [x] - 14_CUL_WS
- @new_bit_msg[4 .. 7] = reverse @bit_msg[$datastart .. $datastart+3]; # [2] Sensortyp
- @new_bit_msg[0 .. 3] = reverse @bit_msg[$datastart+5 .. $datastart+8]; # [1] Sensoradresse
- @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
- @new_bit_msg[8 .. 11] = reverse @bit_msg[$datastart+15 .. $datastart+18]; # [3] T 1, R MID, Wi 1, B 10, Py 10
- if ($typ == 0 || $typ == 2) { # Thermo (AS3), Rain (S2000R, WS7000-16)
- @new_bit_msg[16 .. 19] = reverse @bit_msg[$datastart+20 .. $datastart+23]; # [5] T 10, R MSN
- } else {
- @new_bit_msg[20 .. 23] = reverse @bit_msg[$datastart+20 .. $datastart+23]; # [6] T 10, Wi 10, B 100, Py 100
- @new_bit_msg[16 .. 19] = reverse @bit_msg[$datastart+25 .. $datastart+28]; # [5] H 0.1, Wr 1, B Fak, Py Fak
- if ($typ == 1 || $typ == 3 || $typ == 4 || $typ == 7) { # Thermo/Hygro, Wind, Thermo/Hygro/Baro, Kombi
- @new_bit_msg[28 .. 31] = reverse @bit_msg[$datastart+30 .. $datastart+33]; # [8] H 1, Wr 10
- @new_bit_msg[24 .. 27] = reverse @bit_msg[$datastart+35 .. $datastart+38]; # [7] H 10, Wr 100
- if ($typ == 4) { # Thermo/Hygro/Baro (S2001I, S2001ID)
- @new_bit_msg[36 .. 39] = reverse @bit_msg[$datastart+40 .. $datastart+43]; # [10] P 1
- @new_bit_msg[32 .. 35] = reverse @bit_msg[$datastart+45 .. $datastart+48]; # [9] P 10
- @new_bit_msg[44 .. 47] = reverse @bit_msg[$datastart+50 .. $datastart+53]; # [12] P 100
- @new_bit_msg[40 .. 43] = reverse @bit_msg[$datastart+55 .. $datastart+58]; # [11] P Null
- }
- }
- }
- return (1, @new_bit_msg);
- }
- }
- sub SIGNALduino_postDemo_WS7053($@) {
- my ($name, @bit_msg) = @_;
- my $msg = join("",@bit_msg);
- my $new_msg ="";
- my $parity = 0; # Parity even
- if (length($msg) > 32) { # start not correct
- $msg = substr($msg,1)
- }
- Log3 $name, 4, "$name: WS7053 MSG = $msg";
- if (substr($msg,0,8) ne "10100000") { # check ident
- Log3 $name, 3, "$name: WS7053 ERROR - Ident not 1010 0000 - " . substr($msg,0,8);
- return 0, undef;
- } else {
- for(my $i = 15; $i < 28; $i++) { # Parity over bit 15 and 12 bit temperature
- $parity += substr($msg, $i, 1);
- }
- if ($parity % 2 != 0) {
- Log3 $name, 3, "$name: WS7053 ERROR - Parity not even";
- return 0, undef;
- } else {
- 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);
- # Format from 7053: Bit 0-7 Ident, Bit 8-15 Rolling Code/Parity, Bit 16-27 Temperature (12.3), Bit 28-31 Zero
- $new_msg = substr($msg,0,28) . substr($msg,16,8) . substr($msg,28,4);
- # 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
- 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);
- return (1,split("",$new_msg));
- }
- }
- }
- # manchester method
- sub SIGNALduino_MCTFA
- {
- my ($name,$bitData,$id,$mcbitnum) = @_;
-
- my $preamble_pos;
- my $message_end;
- my $message_length;
-
- #if ($bitData =~ m/^.?(1){16,24}0101/) {
- if ($bitData =~ m/(1{10}101)/ )
- {
- $preamble_pos=$+[1];
- Log3 $name, 4, "$name: TFA 30.3208.0 preamble_pos = $preamble_pos";
- return return (-1," sync not found") if ($preamble_pos <=0);
- my @messages;
-
- do
- {
- $message_end = index($bitData,"1111111111101",$preamble_pos);
- if ($message_end < $preamble_pos)
- {
- $message_end=length($bitData);
- }
- $message_length = ($message_end - $preamble_pos);
-
- my $part_str=substr($bitData,$preamble_pos,$message_length);
- $part_str = substr($part_str,0,52) if (length($part_str)) > 52;
- Log3 $name, 4, "$name: TFA message start=$preamble_pos end=$message_end with length".$message_length;
- Log3 $name, 5, "$name: part $part_str";
- my $hex=SIGNALduino_b2h($part_str);
- push (@messages,$hex);
- Log3 $name, 4, "$name: ".$hex;
- $preamble_pos=index($bitData,"1101",$message_end)+4;
- } while ( $message_end < length($bitData) );
-
- my %seen;
- my @dupmessages = map { 1==$seen{$_}++ ? $_ : () } @messages;
-
- if (scalar(@dupmessages) > 0 ) {
- Log3 $name, 4, "$name: repeated hex ".$dupmessages[0]." found ".$seen{$dupmessages[0]}." times";
- return (1,$dupmessages[0]);
- } else {
- return (-1," no duplicate found");
- }
- }
- return (-1,undef);
-
- }
- sub SIGNALduino_OSV2()
- {
- my ($name,$bitData,$id,$mcbitnum) = @_;
-
- my $preamble_pos;
- my $message_end;
- my $message_length;
-
- #$bitData =~ tr/10/01/;
- if ($bitData =~ m/^.?(01){12,17}.?10011001/)
- { # Valid OSV2 detected!
- #$preamble_pos=index($bitData,"10011001",24);
- $preamble_pos=$+[1];
-
- Log3 $name, 4, "$name: OSV2 protocol detected: preamble_pos = $preamble_pos";
- return return (-1," sync not found") if ($preamble_pos <=24);
-
- $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)
- if (!defined($message_end) || $message_end < $preamble_pos) {
- $message_end = length($bitData);
- } else {
- $message_end += 16;
- Log3 $name, 4, "$name: OSV2 message end pattern found at pos $message_end lengthBitData=".length($bitData);
- }
- $message_length = ($message_end - $preamble_pos)/2;
- return (-1," message is to short") if (defined($ProtocolListSIGNALduino{$id}{length_min}) && $message_length < $ProtocolListSIGNALduino{$id}{length_min} );
- return (-1," message is to long") if (defined($ProtocolListSIGNALduino{$id}{length_max}) && $message_length > $ProtocolListSIGNALduino{$id}{length_max} );
-
- my $idx=0;
- my $osv2bits="";
- my $osv2hex ="";
-
- for ($idx=$preamble_pos;$idx<$message_end;$idx=$idx+16)
- {
- if ($message_end-$idx < 8 )
- {
- last;
- }
- my $osv2byte = "";
- $osv2byte=NULL;
- $osv2byte=substr($bitData,$idx,16);
- my $rvosv2byte="";
-
- for (my $p=0;$p<length($osv2byte);$p=$p+2)
- {
- $rvosv2byte = substr($osv2byte,$p,1).$rvosv2byte;
- }
- $rvosv2byte =~ tr/10/01/;
-
- if (length($rvosv2byte) eq 8) {
- $osv2hex=$osv2hex.sprintf('%02X', oct("0b$rvosv2byte")) ;
- } else {
- $osv2hex=$osv2hex.sprintf('%X', oct("0b$rvosv2byte")) ;
- }
- $osv2bits = $osv2bits.$rvosv2byte;
- }
- $osv2hex = sprintf("%02X", length($osv2hex)*4).$osv2hex;
- Log3 $name, 4, "$name: OSV2 protocol converted to hex: ($osv2hex) with length (".(length($osv2hex)*4).") bits";
- #$found=1;
- #$dmsg=$osv2hex;
- return (1,$osv2hex);
- }
- elsif ($bitData =~ m/^.?(1){16,24}0101/) { # Valid OSV3 detected!
- $preamble_pos = index($bitData, '0101', 16);
- $message_end = length($bitData);
- $message_length = $message_end - ($preamble_pos+4);
- Log3 $name, 4, "$name: OSV3 protocol detected: preamble_pos = $preamble_pos, message_length = $message_length";
-
- my $idx=0;
- #my $osv3bits="";
- my $osv3hex ="";
-
- for ($idx=$preamble_pos+4;$idx<length($bitData);$idx=$idx+4)
- {
- if (length($bitData)-$idx < 4 )
- {
- last;
- }
- my $osv3nibble = "";
- $osv3nibble=NULL;
- $osv3nibble=substr($bitData,$idx,4);
- my $rvosv3nibble="";
-
- for (my $p=0;$p<length($osv3nibble);$p++)
- {
- $rvosv3nibble = substr($osv3nibble,$p,1).$rvosv3nibble;
- }
- $osv3hex=$osv3hex.sprintf('%X', oct("0b$rvosv3nibble"));
- #$osv3bits = $osv3bits.$rvosv3nibble;
- }
- Log3 $name, 4, "$name: OSV3 protocol = $osv3hex";
- my $korr = 10;
- # Check if nibble 1 is A
- if (substr($osv3hex,1,1) ne 'A')
- {
- my $n1=substr($osv3hex,1,1);
- $korr = hex(substr($osv3hex,3,1));
- substr($osv3hex,1,1,'A'); # nibble 1 = A
- substr($osv3hex,3,1,$n1); # nibble 3 = nibble1
- }
- # Korrektur nibble
- my $insKorr = sprintf('%X', $korr);
- # Check for ending 00
- if (substr($osv3hex,-2,2) eq '00')
- {
- #substr($osv3hex,1,-2); # remove 00 at end
- $osv3hex = substr($osv3hex, 0, length($osv3hex)-2);
- }
- my $osv3len = length($osv3hex);
- $osv3hex .= '0';
- my $turn0 = substr($osv3hex,5, $osv3len-4);
- my $turn = '';
- for ($idx=0; $idx<$osv3len-5; $idx=$idx+2) {
- $turn = $turn . substr($turn0,$idx+1,1) . substr($turn0,$idx,1);
- }
- $osv3hex = substr($osv3hex,0,5) . $insKorr . $turn;
- $osv3hex = substr($osv3hex,0,$osv3len+1);
- $osv3hex = sprintf("%02X", length($osv3hex)*4).$osv3hex;
- Log3 $name, 4, "$name: OSV3 protocol converted to hex: ($osv3hex) with length (".((length($osv3hex)-2)*4).") bits";
- #$found=1;
- #$dmsg=$osv2hex;
- return (1,$osv3hex);
-
- }
- return (-1,undef);
- }
- sub SIGNALduino_OSV1()
- {
- my ($name,$bitData,$id,$mcbitnum) = @_;
-
- return (-1," message is to short") if (defined($ProtocolListSIGNALduino{$id}{length_min}) && $mcbitnum < $ProtocolListSIGNALduino{$id}{length_min} );
- return (-1," message is to long") if (defined($ProtocolListSIGNALduino{$id}{length_max}) && $mcbitnum > $ProtocolListSIGNALduino{$id}{length_max} );
-
-
- my $calcsum = oct( "0b" . reverse substr($bitData,0,8));
- $calcsum += oct( "0b" . reverse substr($bitData,8,8));
- $calcsum += oct( "0b" . reverse substr($bitData,16,8));
- $calcsum = ($calcsum & 0xFF) + ($calcsum >> 8);
- my $checksum = oct( "0b" . reverse substr($bitData,24,8));
- if ($calcsum != $checksum) { # Checksum
- return (-1,"OSV1 - ERROR checksum not equal: $calcsum != $checksum");
- } else {
- Log3 $name, 4, "$name: OSV1 input data: $bitData";
- my $newBitData = "00001010"; # Byte 0: Id1 = 0x0A
- $newBitData .= "01001101"; # Byte 1: Id2 = 0x4D
- # Todo: Sensortyp automtisch erkennen und Premable damit setzen.
-
- # preamble => '50B208', # THR128 ohne Checksumme
- # 50 - Length
- # B2 - Byte 0: Id1
- # 08 - Byte 1: Id2
- my $channel = substr($bitData,6,2); # Byte 2 h: Channel
- if ($channel == "00") { # in 0 LSB first
- $newBitData .= "0001"; # out 1 MSB first
- } elsif ($channel == "10") { # in 4 LSB first
- $newBitData .= "0010"; # out 2 MSB first
- } else { # in 8 LSB first
- $newBitData .= "0100"; # out 4 MSB first
- }
- $newBitData .= "0000"; # Byte 2 l: ????
- $newBitData .= "0000"; # Byte 3 h: address
- $newBitData .= reverse substr($bitData,0,4); # Byte 3 l: address (Rolling Code)
- $newBitData .= reverse substr($bitData,8,4); # Byte 4 h: T 0,1
- $newBitData .= "0" . substr($bitData,23,1) . "00"; # Byte 4 l: Bit 2 - Batterie 0=ok, 1=low (< 2,5 Volt)
- $newBitData .= reverse substr($bitData,16,4); # Byte 5 h: T 10
- $newBitData .= reverse substr($bitData,12,4); # Byte 5 l: T 1
- $newBitData .= "0000"; # Byte 6 h: immer 0000
- $newBitData .= substr($bitData,21,1) . "000"; # Byte 6 l: Bit 3 - Temperatur 0=pos | 1=neg, Rest 0
- $newBitData .= "00000000"; # Byte 7: immer 0000 0000
- # calculate new checksum over first 16 nibbles
- $checksum = 0;
- for (my $i = 0; $i < 64; $i = $i + 4) {
- $checksum += oct( "0b" . substr($newBitData, $i, 4));
- }
- $checksum = ($checksum - 0xa) & 0xff;
- $newBitData .= sprintf("%08b",$checksum); # Byte 8: new Checksum
- $newBitData .= "00000000"; # Byte 9: immer 0000 0000
- my $osv1hex = "50" . SIGNALduino_b2h($newBitData); # output with length before #todo: Länge berechnen
- Log3 $name, 4, "$name: OSV1 protocol id ($id) translated to RFXSensor format";
- Log3 $name, 4, "$name: converted to hex: ($osv1hex)";
- return (1,$osv1hex);
- }
- }
- sub SIGNALduino_AS()
- {
- my ($name,$bitData,$id,$mcbitnum) = @_;
- my $debug = AttrVal($name,"debug",0);
-
- if(index($bitData,"1100",16) >= 0) # $rawData =~ m/^A{2,3}/)
- { # Valid AS detected!
- my $message_start = index($bitData,"1100",16);
- Debug "$name: AS protocol detected \n" if ($debug);
-
- my $message_end=index($bitData,"1100",$message_start+16);
- $message_end = length($bitData) if ($message_end == -1);
- my $message_length = $message_end - $message_start;
-
- return (-1," message is to short") if (defined($ProtocolListSIGNALduino{$id}{length_min}) && $message_length < $ProtocolListSIGNALduino{$id}{length_min} );
- return (-1," message is to long") if (defined($ProtocolListSIGNALduino{$id}{length_max}) && $message_length > $ProtocolListSIGNALduino{$id}{length_max} );
-
-
- my $msgbits =substr($bitData,$message_start);
-
- my $ashex=sprintf('%02X', oct("0b$msgbits"));
- Log3 $name, 5, "$name: AS protocol converted to hex: ($ashex) with length ($message_length) bits \n";
- return (1,$bitData);
- }
- return (-1,undef);
- }
- sub SIGNALduino_Hideki()
- {
- my ($name,$bitData,$id,$mcbitnum) = @_;
- my $debug = AttrVal($name,"debug",0);
-
- Debug "$name: search in $bitData \n" if ($debug);
- my $message_start = index($bitData,"10101110");
- if ($message_start >= 0 ) # 0x75 but in reverse order
- {
- Debug "$name: Hideki protocol detected \n" if ($debug);
- # Todo: Mindest Laenge fuer startpunkt vorspringen
- # Todo: Wiederholung auch an das Modul weitergeben, damit es dort geprueft werden kann
- 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
- $message_end = length($bitData) if ($message_end == -1);
- my $message_length = $message_end - $message_start;
-
- return (-1,"message is to short") if (defined($ProtocolListSIGNALduino{$id}{length_min}) && $message_length < $ProtocolListSIGNALduino{$id}{length_min} );
- return (-1,"message is to long") if (defined($ProtocolListSIGNALduino{$id}{length_max}) && $message_length > $ProtocolListSIGNALduino{$id}{length_max} );
-
- my $hidekihex;
- my $idx;
-
- for ($idx=$message_start; $idx<$message_end; $idx=$idx+9)
- {
- my $byte = "";
- $byte= substr($bitData,$idx,8); ## Ignore every 9th bit
- Debug "$name: byte in order $byte " if ($debug);
- $byte = scalar reverse $byte;
- Debug "$name: byte reversed $byte , as hex: ".sprintf('%X', oct("0b$byte"))."\n" if ($debug);
- $hidekihex=$hidekihex.sprintf('%02X', oct("0b$byte"));
- }
- Log3 $name, 4, "$name: hideki protocol converted to hex: $hidekihex with " .$message_length ." bits, messagestart $message_start";
- return (1,$hidekihex); ## Return only the original bits, include length
- }
- return (-1,"Start pattern (10101110) not found");
- }
- sub SIGNALduino_Maverick()
- {
- my ($name,$bitData,$id,$mcbitnum) = @_;
- my $debug = AttrVal($name,"debug",0);
- if ($bitData =~ m/^.*(101010101001100110010101).*/)
- { # Valid Maverick header detected
- my $header_pos=$+[1];
-
- Log3 $name, 4, "$name: Maverick protocol detected: header_pos = $header_pos";
- my $hex=SIGNALduino_b2h(substr($bitData,$header_pos,26*4));
-
- return (1,$hex); ## Return the bits unchanged in hex
- } else {
- return return (-1," header not found");
- }
- }
- sub SIGNALduino_OSPIR()
- {
- my ($name,$bitData,$id,$mcbitnum) = @_;
- my $debug = AttrVal($name,"debug",0);
- if ($bitData =~ m/^.*(1{14}|0{14}).*/)
- { # Valid Oregon PIR detected
- my $header_pos=$+[1];
-
- Log3 $name, 4, "$name: Oregon PIR protocol detected: header_pos = $header_pos";
- my $hex=SIGNALduino_b2h($bitData);
-
- return (1,$hex); ## Return the bits unchanged in hex
- } else {
- return return (-1," header not found");
- }
- }
- sub SIGNALduino_MCRAW()
- {
- my ($name,$bitData,$id,$mcbitnum) = @_;
- my $debug = AttrVal($name,"debug",0);
- my $hex=SIGNALduino_b2h($bitData);
- return (1,$hex); ## Return the bits unchanged in hex
- }
- sub SIGNALduino_SomfyRTS()
- {
- my ($name, $bitData,$id,$mcbitnum) = @_;
-
- #(my $negBits = $bitData) =~ tr/10/01/; # Todo: eventuell auf pack umstellen
- if (defined($mcbitnum)) {
- Log3 $name, 4, "$name: Somfy bitdata: $bitData ($mcbitnum)";
- if ($mcbitnum == 57) {
- $bitData = substr($bitData, 1, 56);
- Log3 $name, 4, "$name: Somfy bitdata: _$bitData (" . length($bitData) . "). Bit am Anfang entfernt";
- }
- }
- my $encData = SIGNALduino_b2h($bitData);
- #Log3 $name, 4, "$name: Somfy RTS protocol enc: $encData";
- return (1, $encData);
- }
- # - - - - - - - - - - - -
- #=item SIGNALduino_filterMC()
- #This functons, will act as a filter function. It will decode MU data via Manchester encoding
- #
- # Will return $count of ???, modified $rawData , modified %patternListRaw,
- # =cut
- sub SIGNALduino_filterMC($$$%)
- {
-
- ## Warema Implementierung : Todo variabel gestalten
- my ($name,$id,$rawData,%patternListRaw) = @_;
- my $debug = AttrVal($name,"debug",0);
-
- my ($ht, $hasbit, $value) = 0;
- $value=1 if (!$debug);
- my @bitData;
- my @sigData = split "",$rawData;
- foreach my $pulse (@sigData)
- {
- next if (!defined($patternListRaw{$pulse}));
- #Log3 $name, 4, "$name: pulese: ".$patternListRaw{$pulse};
-
- if (SIGNALduino_inTol($ProtocolListSIGNALduino{$id}{clockabs},abs($patternListRaw{$pulse}),$ProtocolListSIGNALduino{$id}{clockabs}*0.5))
- {
- # Short
- $hasbit=$ht;
- $ht = $ht ^ 0b00000001;
- $value='S' if($debug);
- #Log3 $name, 4, "$name: filter S ";
- } elsif ( SIGNALduino_inTol($ProtocolListSIGNALduino{$id}{clockabs}*2,abs($patternListRaw{$pulse}),$ProtocolListSIGNALduino{$id}{clockabs}*0.5)) {
- # Long
- $hasbit=1;
- $ht=1;
- $value='L' if($debug);
- #Log3 $name, 4, "$name: filter L ";
- } elsif ( SIGNALduino_inTol($ProtocolListSIGNALduino{$id}{syncabs}+(2*$ProtocolListSIGNALduino{$id}{clockabs}),abs($patternListRaw{$pulse}),$ProtocolListSIGNALduino{$id}{clockabs}*0.5)) {
- $hasbit=1;
- $ht=1;
- $value='L' if($debug);
- #Log3 $name, 4, "$name: sync L ";
-
- } else {
- # No Manchester Data
- $ht=0;
- $hasbit=0;
- #Log3 $name, 4, "$name: filter n ";
- }
-
- if ($hasbit && $value) {
- $value = lc($value) if($debug && $patternListRaw{$pulse} < 0);
- my $bit=$patternListRaw{$pulse} > 0 ? 1 : 0;
- #Log3 $name, 5, "$name: adding value: ".$bit;
-
- push @bitData, $bit ;
- }
- }
- my %patternListRawFilter;
-
- $patternListRawFilter{0} = 0;
- $patternListRawFilter{1} = $ProtocolListSIGNALduino{$id}{clockabs};
-
- #Log3 $name, 5, "$name: filterbits: ".@bitData;
- $rawData = join "", @bitData;
- return (undef ,$rawData, %patternListRawFilter);
-
- }
- # - - - - - - - - - - - -
- #=item SIGNALduino_filterSign()
- #This functons, will act as a filter function. It will remove the sign from the pattern, and compress message and pattern
- #
- # Will return $count of combined values, modified $rawData , modified %patternListRaw,
- # =cut
- sub SIGNALduino_filterSign($$$%)
- {
- my ($name,$id,$rawData,%patternListRaw) = @_;
- my $debug = AttrVal($name,"debug",0);
- my %buckets;
- # Remove Sign
- %patternListRaw = map { $_ => abs($patternListRaw{$_})} keys %patternListRaw; ## remove sign from all
-
- my $intol=0;
- my $cnt=0;
- # compress pattern hash
- foreach my $key (keys %patternListRaw) {
-
- #print "chk:".$patternListRaw{$key};
- #print "\n";
- $intol=0;
- foreach my $b_key (keys %buckets){
- #print "with:".$buckets{$b_key};
- #print "\n";
-
- # $value - $set <= $tolerance
- if (SIGNALduino_inTol($patternListRaw{$key},$buckets{$b_key},$buckets{$b_key}*0.25))
- {
- #print"\t". $patternListRaw{$key}."($key) is intol of ".$buckets{$b_key}."($b_key) \n";
- $cnt++;
- eval "\$rawData =~ tr/$key/$b_key/";
- #if ($key == $msg_parts{clockidx})
- #{
- # $msg_pats{syncidx} = $buckets{$key};
- # }
- # elsif ($key == $msg_parts{syncidx})
- # {
- # $msg_pats{syncidx} = $buckets{$key};
- # }
-
- $buckets{$b_key} = ($buckets{$b_key} + $patternListRaw{$key}) /2;
- #print"\t recalc to ". $buckets{$b_key}."\n";
- delete ($patternListRaw{$key}); # deletes the compressed entry
- $intol=1;
- last;
- }
- }
- if ($intol == 0) {
- $buckets{$key}=abs($patternListRaw{$key});
- }
- }
- return ($cnt,$rawData, %patternListRaw);
- #print "rdata: ".$msg_parts{rawData}."\n";
- #print Dumper (%buckets);
- #print Dumper (%msg_parts);
- #modify msg_parts pattern hash
- #$patternListRaw = \%buckets;
- }
- # - - - - - - - - - - - -
- #=item SIGNALduino_compPattern()
- #This functons, will act as a filter function. It will remove the sign from the pattern, and compress message and pattern
- #
- # Will return $count of combined values, modified $rawData , modified %patternListRaw,
- # =cut
- sub SIGNALduino_compPattern($$$%)
- {
- my ($name,$id,$rawData,%patternListRaw) = @_;
- my $debug = AttrVal($name,"debug",0);
- my %buckets;
- # Remove Sign
- #%patternListRaw = map { $_ => abs($patternListRaw{$_})} keys %patternListRaw; ## remove sing from all
-
- my $intol=0;
- my $cnt=0;
- # compress pattern hash
- foreach my $key (keys %patternListRaw) {
-
- #print "chk:".$patternListRaw{$key};
- #print "\n";
- $intol=0;
- foreach my $b_key (keys %buckets){
- #print "with:".$buckets{$b_key};
- #print "\n";
-
- # $value - $set <= $tolerance
- if (SIGNALduino_inTol($patternListRaw{$key},$buckets{$b_key},$buckets{$b_key}*0.4))
- {
- #print"\t". $patternListRaw{$key}."($key) is intol of ".$buckets{$b_key}."($b_key) \n";
- $cnt++;
- eval "\$rawData =~ tr/$key/$b_key/";
- #if ($key == $msg_parts{clockidx})
- #{
- # $msg_pats{syncidx} = $buckets{$key};
- # }
- # elsif ($key == $msg_parts{syncidx})
- # {
- # $msg_pats{syncidx} = $buckets{$key};
- # }
-
- $buckets{$b_key} = ($buckets{$b_key} + $patternListRaw{$key}) /2;
- #print"\t recalc to ". $buckets{$b_key}."\n";
- delete ($patternListRaw{$key}); # deletes the compressed entry
- $intol=1;
- last;
- }
- }
- if ($intol == 0) {
- $buckets{$key}=$patternListRaw{$key};
- }
- }
- return ($cnt,$rawData, %patternListRaw);
- #print "rdata: ".$msg_parts{rawData}."\n";
- #print Dumper (%buckets);
- #print Dumper (%msg_parts);
- #modify msg_parts pattern hash
- #$patternListRaw = \%buckets;
- }
- #print Dumper (%msg_parts);
- #print "\n";
- #SIGNALduino_filterSign(%msg_parts);
- #print Dumper (%msg_parts);
- #print "\n";
- 1;
- =pod
- =item summary supports the same low-cost receiver for digital signals
- =item summary_DE Unterstützt den gleichnamigen Low-Cost Empfänger fuer digitale Signale
- =begin html
- <a name="SIGNALduino"></a>
- <h3>SIGNALduino</h3>
- <table>
- <tr><td>
- The SIGNALduino ia based on an idea from mdorenka published at <a
- href="http://forum.fhem.de/index.php/topic,17196.0.html">FHEM Forum</a>.
- With the opensource firmware (see this <a
- href="https://github.com/RFD-FHEM/SIGNALduino">link</a>) it is capable
- to receive and send different protocols over different medias. Currently are 433Mhz protocols implemented.
- <br><br>
- The following device support is currently available:
- <br><br>
- Wireless switches <br>
- ITv1 & ITv3/Elro and other brands using pt2263 or arctech protocol--> uses IT.pm<br><br>
- 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>
- <br><br>
- Temperatur / humidity senso
- <ul>
- <li>PEARL NC7159, LogiLink WS0002,GT-WT-02,AURIOL,TCM97001, TCM27 and many more -> 14_CUL_TCM97001 </li>
- <li>Oregon Scientific v2 and v3 Sensors -> 41_OREGON.pm</li>
- <li>Temperatur / humidity sensors suppored -> 14_SD_WS07</li>
- <li>technoline WS 6750 and TX70DTH -> 14_SD_WS07</li>
- <li>Eurochon EAS 800z -> 14_SD_WS07</li>
- <li>CTW600, WH1080 -> 14_SD_WS09 </li>
- <li>Hama TS33C, Bresser Thermo/Hygro Sensor -> 14_Hideki</li>
- <li>FreeTec Aussenmodul NC-7344 -> 14_SD_WS07</li>
- </ul>
- <br><br>
- It is possible to attach more than one device in order to get better
- reception, fhem will filter out duplicate messages.<br><br>
- Note: this module require the Device::SerialPort or Win32::SerialPort
- module. It can currently only attatched via USB.
- </td>
- </tr>
- </table>
- <br>
- <a name="SIGNALduinodefine"></a>
- <b>Define</b><br>
- <code>define <name> SIGNALduino <device> </code> <br>
- <br>
- USB-connected devices (SIGNALduino):<br>
- <ul><li>
- <device> specifies the serial port to communicate with the SIGNALduino.
- The name of the serial-device depends on your distribution, under
- linux the cdc_acm kernel module is responsible, and usually a
- /dev/ttyACM0 or /dev/ttyUSB0 device will be created. If your distribution does not have a
- cdc_acm module, you can force usbserial to handle the SIGNALduino by the
- following command:
- <ul>
- modprobe usbserial
- vendor=0x03eb
- product=0x204b
- </ul>In this case the device is most probably
- /dev/ttyUSB0.<br><br>
- You can also specify a baudrate if the device name contains the @
- character, e.g.: /dev/ttyACM0@57600<br><br>This is also the default baudrate
- It is recommended to specify the device via a name which does not change:
- e.g. via by-id devicename: /dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0@57600
- If the baudrate is "directio" (e.g.: /dev/ttyACM0@directio), then the
- perl module Device::SerialPort is not needed, and fhem opens the device
- with simple file io. This might work if the operating system uses sane
- defaults for the serial parameters, e.g. some Linux distributions and
- OSX. <br><br>
- </li>
- </ul>
- <a name="SIGNALduinoattr"></a>
- <b>Attributes</b>
- <ul>
- <li><a name="addvaltrigger">addvaltrigger</a><br>
- Create triggers for additional device values. Right now these are RSSI, RAWMSG and DMSG.
- </li>
- <li>blacklist_IDs<br>
- The blacklist works only if a whitelist not exist.
- </li>
- <li>cc1101_frequency<br>
- Since the PA table values are frequency-dependent, is at 868 MHz a value greater 800 required.
- </li>
- <li><a href="#do_not_notify">do_not_notify</a></li>
- <li><a href="#attrdummy">dummy</a></li>
- <li>debug<br>
- This will bring the module in a very verbose debug output. Usefull to find new signals and verify if the demodulation works correctly.
- </li>
- <li>development<br>
- With development you can enable protocol decoding for protocolls witch are still in development and may not be very accurate implemented.
- This can result in crashes or throw high amount of log entrys in your logfile, so be careful to use this. <br><br>
-
- Protocols flagged with a developID flag are not loaded unless specified to do so.<br>
-
- 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>
- Specify "y" followed with the protocol id to enable it.<br><br>
- If the protocoll is developed well, but the logical module is not ready, developId => 'm' is set.<br>
- You can enable it with the attribute:<br>
- Specify "m" followed with the protocol id to enable it.<br>
- </li>
- <li>doubleMsgCheck_IDs<br>
- This attribute allows it, to specify protocols which must be received two equal messages to call dispatch to the modules.<br>
- You can specify multiple IDs wih a colon : 0,3,7,12<br>
- </li>
- <li>flashCommand<br>
- 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>
- The default is: avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]<br>
- It contains some place-holders that automatically get filled with the according values:<br>
- <ul>
- <li>[PORT]<br>
- is the port the Signalduino is connectd to (e.g. /dev/ttyUSB0) and will be used from the defenition</li>
- <li>[HEXFILE]<br>
- is the .hex file that shall get flashed. There are three options (applied in this order):<br>
- - passed in set flash as first argument<br>
- - taken from the hexFile attribute<br>
- - the default value defined in the module<br>
- </li>
- <li>[LOGFILE]<br>
- The logfile that collects information about the flash process. It gets displayed in FHEM after finishing the flash process</li>
- </ul>
-
- </li>
- <li>hardware<br>
- When using the flash command, you should specify what hardware you have connected to the usbport. Doing not, can cause failures of the device.
- </li>
- <li>minsecs<br>
- 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.
- If specified, then supported modules will discard new messages if minsecs isn't past.
- </li>
-
- <li>noMsgVerbose<br>
- With this attribute you can control the logging of debug messages from the io device.
- If set to 3, this messages are logged if global verbose is set to 3 or higher.
- </li>
- <li>longids<br>
- 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>
- Default is to not to use long IDs for all devices.
- <br><br>
- Examples:<PRE>
- # Do not use any long IDs for any devices:
- attr sduino longids 0
- # Use any long IDs for all devices (this is default):
- attr sduino longids 1
- # Use longids for BTHR918N devices.
- # Will generate devices names like BTHR918N_f3.
- attr sduino longids BTHR918N
- </PRE></li>
- <li>rawmsgEvent<br>
- When set to "1" received raw messages triggers events
- </li>
- <li>suppressDeviceRawmsg<br>
- When set to 1, the internal "RAWMSG" will not be updated with the received messages
- </li>
- <li>whitelistIDs<br>
- This attribute allows it, to specify whichs protocos are considured from this module.
- Protocols which are not considured, will not generate logmessages or events. They are then completly ignored.
- This makes it possible to lower ressource usage and give some better clearnes in the logs.
- You can specify multiple whitelistIDs wih a colon : 0,3,7,12<br>
- With a # at the beginnging whitelistIDs can be deactivated.
- </li><br>
- <li>WS09_CRCAUS<br>
- <br>0: CRC-Check WH1080 CRC = 0 on, default
- <br>2: CRC = 49 (x031) WH1080, set OK
- </li>
- </ul>
-
-
-
- <a name="SIGNALduinoget"></a>
- <b>Get</b>
- <ul>
- <li>version<br>
- return the SIGNALduino firmware version
- </li><br>
- <li>raw<br>
- Issue a SIGNALduino firmware command, and wait for one line of data returned by
- the SIGNALduino. See the SIGNALduino firmware code for details on SIGNALduino
- commands. With this line, you can send almost any signal via a transmitter connected
- </li><br>
- <li>cmds<br>
- Depending on the firmware installed, SIGNALduinos have a different set of
- possible commands. Please refer to the sourcecode of the firmware of your
- SIGNALduino to interpret the response of this command. See also the raw-
- command.
- </li><br>
- <li>protocolIDs<br>
- display a list of the protocol IDs
- </li><br>
- <li>ccconf<br>
- Only with cc1101 receiver.
- Read some CUL radio-chip (cc1101) registers (frequency, bandwidth, etc.),
- and display them in human readable form.
- </li><br>
- <li>ccpatable<br>
- read cc1101 PA table (power amplification for RF sending)
- </li><br>
- <li>ccreg<br>
- read cc1101 registers (99 reads all cc1101 registers)
- </li><br>
- </ul>
- <a name="SIGNALduinoset"></a>
- <b>SET</b>
- <ul>
- <li>raw<br>
- Issue a SIGNALduino firmware command, without waiting data returned by
- the SIGNALduino. See the SIGNALduino firmware code for details on SIGNALduino
- commands. With this line, you can send almost any signal via a transmitter connected
- To send some raw data look at these examples:
- P<protocol id>#binarydata#R<num of repeats>#C<optional clock> (#C is optional)
- <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
- <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
- <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
- <br>;
- </p>
- </li><br>
- <li>reset<br>
- This will do a reset of the usb port and normaly causes to reset the uC connected.
- </li><br>
- <li>close<br>
- Closes the connection to the device.
- </li><br>
- <li>flash [hexFile|url]<br>
- 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
- arduino IDE to flash the firmware into the SIGNALduino this provides a way to flash it directly from FHEM.
- You can specify a file on your fhem server or specify a url from which the firmware is downloaded
- There are some requirements:
- <ul>
- <li>avrdude must be installed on the host<br>
- On a Raspberry PI this can be done with: sudo apt-get install avrdude</li>
- <li>the hardware attribute must be set if using any other hardware as an Arduino nano<br>
- This attribute defines the command, that gets sent to avrdude to flash the uC.<br></li>
- <br>
-
- </ul>
- </li>
- <li>sendMsg<br>
- This command will create the needed instructions for sending raw data via the signalduino. Insteaf of specifying the signaldata by your own you specify
- a protocol and the bits you want to send. The command will generate the needed command, that the signalduino will send this.
- <br><br>
- Please note, that this command will work only for MU or MS protocols. You can't transmit manchester data this way.
- <br><br>
- Input args are:
- <p>
- P<protocol id>#binarydata#R<num of repeats>#C<optional clock> (#C is optional)
- <br>Example: P0#0101#R3#C500
- <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.
- <br>SR;R=3;P0=500;P1=-9000;P2=-4000;P3=-2000;D=03020302;
- </p>
-
- </li><br>
- <li>enableMessagetype<br>
- Allows you to enable the message processing for
- <ul>
- <li>messages with sync (syncedMS),</li>
- <li>messages without a sync pulse (unsyncedMU) </li>
- <li>manchester encoded messages (manchesterMC) </li>
- </ul>
- The new state will be saved into the eeprom of your arduino.
- </li><br>
- <li>disableMessagetype<br>
- Allows you to disable the message processing for
- <ul>
- <li>messages with sync (syncedMS),</li>
- <li>messages without a sync pulse (unsyncedMU)</li>
- <li>manchester encoded messages (manchesterMC) </li>
- </ul>
- The new state will be saved into the eeprom of your arduino.
- </li><br><br>
-
- <li>freq / bWidth / patable / rAmpl / sens<br>
- Only with CC1101 receiver.<br>
- Set the sduino frequency / bandwidth / PA table / receiver-amplitude / sensitivity<br>
-
- Use it with care, it may destroy your hardware and it even may be
- illegal to do so. Note: The parameters used for RFR transmission are
- not affected.<br>
- <ul>
- <li>freq sets both the reception and transmission frequency. Note:
- Although the CC1101 can be set to frequencies between 315 and 915
- MHz, the antenna interface and the antenna of the CUL is tuned for
- exactly one frequency. Default is 868.3 MHz (or 433 MHz)</li>
- <li>bWidth can be set to values between 58 kHz and 812 kHz. Large values
- are susceptible to interference, but make possible to receive
- inaccurately calibrated transmitters. It affects tranmission too.
- Default is 325 kHz.</li>
- <li>patable change the PA table (power amplification for RF sending)
- </li>
- <li>rAmpl is receiver amplification, with values between 24 and 42 dB.
- Bigger values allow reception of weak signals. Default is 42.
- </li>
- <li>sens is the decision boundary between the on and off values, and it
- is 4, 8, 12 or 16 dB. Smaller values allow reception of less clear
- signals. Default is 4 dB.</li>
- </ul>
- </li><br>
-
- </ul>
- =end html
- =cut
|