70_ENIGMA2.pm 119 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345
  1. # $Id: 70_ENIGMA2.pm 13387 2017-02-11 13:34:18Z loredo $
  2. ##############################################################################
  3. #
  4. # 70_ENIGMA2.pm
  5. # An FHEM Perl module for controlling ENIGMA2 based TV receivers
  6. # via network connection.
  7. #
  8. # Copyright by Julian Pawlowski
  9. # e-mail: julian.pawlowski at gmail.com
  10. #
  11. # This file is part of fhem.
  12. #
  13. # Fhem is free software: you can redistribute it and/or modify
  14. # it under the terms of the GNU General Public License as published by
  15. # the Free Software Foundation, either version 2 of the License, or
  16. # (at your option) any later version.
  17. #
  18. # Fhem is distributed in the hope that it will be useful,
  19. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. # GNU General Public License for more details.
  22. #
  23. # You should have received a copy of the GNU General Public License
  24. # along with fhem. If not, see <http://www.gnu.org/licenses/>.
  25. #
  26. ##############################################################################
  27. package main;
  28. #use 5.012;
  29. use strict;
  30. use warnings;
  31. use Data::Dumper;
  32. use HttpUtils;
  33. use Encode;
  34. no if $] >= 5.017011, warnings => 'experimental';
  35. no warnings "all";
  36. sub ENIGMA2_Set($@);
  37. sub ENIGMA2_Get($@);
  38. sub ENIGMA2_GetStatus($;$);
  39. sub ENIGMA2_Define($$);
  40. sub ENIGMA2_Undefine($$);
  41. #########################
  42. # Forward declaration for remotecontrol module
  43. sub ENIGMA2_RClayout_TV();
  44. sub ENIGMA2_RCmakenotify($$);
  45. ###################################
  46. sub ENIGMA2_Initialize($) {
  47. my ($hash) = @_;
  48. Log3 $hash, 5, "ENIGMA2_Initialize: Entering";
  49. $hash->{GetFn} = "ENIGMA2_Get";
  50. $hash->{SetFn} = "ENIGMA2_Set";
  51. $hash->{DefFn} = "ENIGMA2_Define";
  52. $hash->{UndefFn} = "ENIGMA2_Undefine";
  53. $hash->{AttrList} =
  54. "https:0,1 http-method:GET,POST http-noshutdown:1,0 disable:0,1 bouquet-tv bouquet-radio timeout remotecontrol:standard,advanced,keyboard lightMode:0,1 ignoreState:0,1 macaddr:textField model wakeupCmd:textField WOL_useUdpBroadcast WOL_port WOL_mode:EW,UDP,BOTH "
  55. . $readingFnAttributes;
  56. $data{RC_layout}{ENIGMA2_DreamMultimedia_DM500_DM800_SVG} =
  57. "ENIGMA2_RClayout_DM800_SVG";
  58. $data{RC_layout}{ENIGMA2_DreamMultimedia_DM500_DM800} =
  59. "ENIGMA2_RClayout_DM800";
  60. $data{RC_layout}{ENIGMA2_DreamMultimedia_DM8000_DM800se_SVG} =
  61. "ENIGMA2_RClayout_DM8000_SVG";
  62. $data{RC_layout}{ENIGMA2_DreamMultimedia_DM8000_DM800se} =
  63. "ENIGMA2_RClayout_DM8000";
  64. $data{RC_layout}{ENIGMA2_DreamMultimedia_RC10_SVG} =
  65. "ENIGMA2_RClayout_RC10_SVG";
  66. $data{RC_layout}{ENIGMA2_DreamMultimedia_RC10} = "ENIGMA2_RClayout_RC10";
  67. # $data{RC_layout}{ENIGMA2_VUplus_Solo2_SVG} = "ENIGMA2_RClayout_VUplusSolo2_SVG";
  68. # $data{RC_layout}{ENIGMA2_VUplus_Solo2} = "ENIGMA2_RClayout_VUplusSolo2";
  69. $data{RC_layout}{ENIGMA2_VUplus_Duo2_SVG} =
  70. "ENIGMA2_RClayout_VUplusDuo2_SVG";
  71. $data{RC_layout}{ENIGMA2_VUplus_Duo2} = "ENIGMA2_RClayout_VUplusDuo2";
  72. # $data{RC_layout}{ENIGMA2_VUplus_Ultimo_SVG} = "ENIGMA2_RClayout_VUplusUltimo_SVG";
  73. # $data{RC_layout}{ENIGMA2_VUplus_Ultimo} = "ENIGMA2_RClayout_VUplusUltimo";
  74. $data{RC_makenotify}{ENIGMA2} = "ENIGMA2_RCmakenotify";
  75. # 98_powerMap.pm support
  76. $hash->{powerMap} = {
  77. model => 'modelid', # fallback to attribute
  78. modelid => {
  79. 'SOLO_SE' => {
  80. rname_E => 'energy',
  81. rname_P => 'consumption',
  82. map => {
  83. stateAV => {
  84. absent => 0.5,
  85. off => 12,
  86. '*' => 13,
  87. },
  88. },
  89. },
  90. },
  91. };
  92. return;
  93. }
  94. #####################################
  95. sub ENIGMA2_GetStatus($;$) {
  96. my ( $hash, $update ) = @_;
  97. my $name = $hash->{NAME};
  98. my $interval = $hash->{INTERVAL};
  99. Log3 $name, 5, "ENIGMA2 $name: called function ENIGMA2_GetStatus()";
  100. RemoveInternalTimer($hash);
  101. InternalTimer( gettimeofday() + $interval, "ENIGMA2_GetStatus", $hash, 0 );
  102. return
  103. if ( AttrVal( $name, "disable", 0 ) == 1 );
  104. if ( !$update ) {
  105. ENIGMA2_SendCommand( $hash, "powerstate" );
  106. }
  107. else {
  108. ENIGMA2_SendCommand( $hash, "getcurrent" );
  109. }
  110. return;
  111. }
  112. ###################################
  113. sub ENIGMA2_Get($@) {
  114. my ( $hash, @a ) = @_;
  115. my $name = $hash->{NAME};
  116. my $what;
  117. Log3 $name, 5, "ENIGMA2 $name: called function ENIGMA2_Get()";
  118. return "argument is missing" if ( int(@a) < 2 );
  119. $what = $a[1];
  120. if ( $what =~
  121. /^(power|input|volume|mute|channel|currentMedia|currentTitle|nextTitle|providername|servicevideosize)$/
  122. )
  123. {
  124. if ( ReadingsVal( $name, $what, "" ) ne "" ) {
  125. return ReadingsVal( $name, $what, "" );
  126. }
  127. else {
  128. return "no such reading: $what";
  129. }
  130. }
  131. # streamUrl
  132. elsif ( $what eq "streamUrl" ) {
  133. if ( defined( $a[2] ) && $a[2] eq "mobile" ) {
  134. return
  135. "http://"
  136. . $hash->{helper}{ADDRESS} . ":"
  137. . $hash->{helper}{PORT}
  138. . "/web/stream.m3u?ref="
  139. . urlEncode( ReadingsVal( $name, "servicereference", "-" ) )
  140. . "&device=phone";
  141. }
  142. else {
  143. return
  144. "http://"
  145. . $hash->{helper}{ADDRESS} . ":"
  146. . $hash->{helper}{PORT}
  147. . "/web/stream.m3u?ref="
  148. . urlEncode( ReadingsVal( $name, "servicereference", "-" ) )
  149. . "&device=etc";
  150. }
  151. }
  152. else {
  153. return
  154. "Unknown argument $what, choose one of power:noArg input:noArg volume:noArg mute:noArg channel:noArg currentMedia:noArg currentTitle:noArg nextTitle:noArg providername:noArg servicevideosize:noArg streamUrl:,mobile ";
  155. }
  156. }
  157. ###################################
  158. sub ENIGMA2_Set($@) {
  159. my ( $hash, @a ) = @_;
  160. my $name = $hash->{NAME};
  161. my $state = ReadingsVal( $name, "state", "absent" );
  162. my $presence = ReadingsVal( $name, "presence", "absent" );
  163. my $input = ReadingsVal( $name, "input", "" );
  164. my $channel = ReadingsVal( $name, "channel", "" );
  165. my $channels = "";
  166. my $ignoreState = AttrVal( $name, "ignoreState", 0 );
  167. Log3 $name, 5, "ENIGMA2 $name: called function ENIGMA2_Set()";
  168. return "No Argument given" if ( !defined( $a[1] ) );
  169. # depending on current FHEMWEB instance's allowedCommands,
  170. # restrict set commands if there is "set-user" in it
  171. my $adminMode = 1;
  172. my $FWallowedCommands = 0;
  173. $FWallowedCommands = AttrVal( $FW_wname, "allowedCommands", 0 )
  174. if ( defined($FW_wname) );
  175. if ( $FWallowedCommands && $FWallowedCommands =~ m/\bset-user\b/ ) {
  176. $adminMode = 0;
  177. return "Forbidden command: set " . $a[1]
  178. if ( lc( $a[1] ) eq "statusrequest"
  179. || lc( $a[1] ) eq "reboot"
  180. || lc( $a[1] ) eq "restartgui"
  181. || lc( $a[1] ) eq "shutdown" );
  182. }
  183. # load channel list
  184. if (
  185. defined($input)
  186. && defined($channel)
  187. && $input ne ""
  188. && $channel ne ""
  189. && ( !defined( $hash->{helper}{bouquet}{$input} )
  190. || !defined( $hash->{helper}{bouquet}{$input}{$channel} ) )
  191. )
  192. {
  193. $channels .= $channel . ",";
  194. }
  195. if ( $input ne ""
  196. && defined( $hash->{helper}{channels}{$input} )
  197. && ref( $hash->{helper}{channels}{$input} ) eq "ARRAY" )
  198. {
  199. $channels .= join( ',', @{ $hash->{helper}{channels}{$input} } );
  200. }
  201. # create inputList reading for frontends
  202. readingsSingleUpdate( $hash, "inputList", "tv,radio", 1 )
  203. if ( ReadingsVal( $name, "inputList", "-" ) ne "tv,radio" );
  204. # create channelList reading for frontends
  205. readingsSingleUpdate( $hash, "channelList", $channels, 1 )
  206. if ( ReadingsVal( $name, "channelList", "-" ) ne $channels );
  207. my $usage =
  208. "Unknown argument "
  209. . $a[1]
  210. . ", choose one of toggle:noArg on:noArg off:noArg volume:slider,0,1,100 volumeUp:noArg volumeDown:noArg msg remoteControl channelUp:noArg channelDown:noArg play:noArg pause:noArg stop:noArg record:noArg showText downmix:on,off channel:"
  211. . $channels;
  212. $usage .= " mute:-,on,off"
  213. if ( ReadingsVal( $name, "mute", "-" ) eq "-" );
  214. $usage .= " mute:on,off"
  215. if ( ReadingsVal( $name, "mute", "-" ) ne "-" );
  216. $usage .= " input:-,tv,radio"
  217. if ( $input eq "-" );
  218. $usage .= " input:tv,radio"
  219. if ( $input ne "-" );
  220. if ($adminMode) {
  221. $usage .= " reboot:noArg";
  222. $usage .= " restartGui:noArg";
  223. $usage .= " shutdown:noArg";
  224. $usage .= " statusRequest:noArg";
  225. }
  226. my $cmd = '';
  227. my $result;
  228. # statusRequest
  229. if ( lc( $a[1] ) eq "statusrequest" ) {
  230. Log3 $name, 3, "ENIGMA2 set $name " . $a[1];
  231. if ( $state ne "absent" ) {
  232. Log3 $name, 4,
  233. "ENIGMA2 $name: Clearing cache for bouquet and channels";
  234. $hash->{helper}{bouquet} = undef;
  235. $hash->{helper}{channels} = undef;
  236. }
  237. ENIGMA2_GetStatus($hash);
  238. }
  239. # toggle
  240. elsif ( lc( $a[1] ) eq "toggle" ) {
  241. if ( $state ne "on" ) {
  242. return ENIGMA2_Set( $hash, $name, "on" );
  243. }
  244. else {
  245. return ENIGMA2_Set( $hash, $name, "off" );
  246. }
  247. }
  248. # shutdown
  249. elsif ( lc( $a[1] ) eq "shutdown" ) {
  250. return "Recordings running"
  251. if ( ReadingsVal( $name, "recordings", "0" ) ne "0" );
  252. Log3 $name, 3, "ENIGMA2 set $name " . $a[1];
  253. if ( $state ne "absent" || $ignoreState ne "0" ) {
  254. $cmd = "newstate=1";
  255. $result =
  256. ENIGMA2_SendCommand( $hash, "powerstate", $cmd, "shutdown" );
  257. }
  258. else {
  259. return "Device needs to be ON to be set to standby mode.";
  260. }
  261. }
  262. # reboot
  263. elsif ( lc( $a[1] ) eq "reboot" ) {
  264. return "Recordings running"
  265. if ( ReadingsVal( $name, "recordings", "0" ) ne "0" );
  266. Log3 $name, 3, "ENIGMA2 set $name " . $a[1];
  267. if ( $state ne "absent" || $ignoreState ne "0" ) {
  268. $cmd = "newstate=2";
  269. $result =
  270. ENIGMA2_SendCommand( $hash, "powerstate", $cmd, "reboot" );
  271. }
  272. else {
  273. return "Device needs to be reachable to be rebooted.";
  274. }
  275. }
  276. # restartGui
  277. elsif ( lc( $a[1] ) eq "restartgui" ) {
  278. return "Recordings running"
  279. if ( ReadingsVal( $name, "recordings", "0" ) ne "0" );
  280. Log3 $name, 3, "ENIGMA2 set $name " . $a[1];
  281. if ( $state eq "on" || $ignoreState ne "0" ) {
  282. $cmd = "newstate=3";
  283. $result =
  284. ENIGMA2_SendCommand( $hash, "powerstate", $cmd, "restartGui" );
  285. }
  286. else {
  287. return "Device needs to be ON to restart the GUI.";
  288. }
  289. }
  290. # on
  291. elsif ( lc( $a[1] ) eq "on" ) {
  292. if ( $state eq "absent" ) {
  293. Log3 $name, 3, "ENIGMA2 set $name " . $a[1] . " (wakeup)";
  294. my $wakeupCmd = AttrVal( $name, "wakeupCmd", "" );
  295. my $macAddr =
  296. AttrVal( $name, "macaddr", ReadingsVal( $name, "lanmac", "" ) );
  297. if ( $wakeupCmd ne "" ) {
  298. $wakeupCmd =~ s/\$DEVICE/$name/g;
  299. $wakeupCmd =~ s/\$MACADDR/$macAddr/g;
  300. if ( $wakeupCmd =~ s/^[ \t]*\{|\}[ \t]*$//g ) {
  301. Log3 $name, 4,
  302. "ENIGMA2 executing wake-up command (Perl): $wakeupCmd";
  303. $result = eval $wakeupCmd;
  304. }
  305. else {
  306. Log3 $name, 4,
  307. "ENIGMA2 executing wake-up command (fhem): $wakeupCmd";
  308. $result = fhem $wakeupCmd;
  309. }
  310. }
  311. elsif ( $macAddr ne "" && $macAddr ne "-" ) {
  312. $result = ENIGMA2_wake( $name, $macAddr );
  313. return "wake-up command sent to MAC $macAddr";
  314. }
  315. else {
  316. return
  317. "Device MAC address unknown. Please turn on the device manually once or set attribute macaddr.";
  318. }
  319. }
  320. else {
  321. Log3 $name, 3, "ENIGMA2 set $name " . $a[1];
  322. $cmd = "newstate=4";
  323. $result = ENIGMA2_SendCommand( $hash, "powerstate", $cmd, "on" );
  324. }
  325. }
  326. # off
  327. elsif ( lc( $a[1] ) eq "off" ) {
  328. if ( $state ne "absent" || $ignoreState ne "0" ) {
  329. Log3 $name, 3, "ENIGMA2 set $name " . $a[1];
  330. $cmd = "newstate=5";
  331. $result = ENIGMA2_SendCommand( $hash, "powerstate", $cmd, "off" );
  332. }
  333. else {
  334. return "Device needs to be reachable to be set to standby mode.";
  335. }
  336. }
  337. # downmix
  338. elsif ( lc( $a[1] ) eq "downmix" ) {
  339. return "No argument given" if ( !defined( $a[2] ) );
  340. Log3 $name, 3, "ENIGMA2 set $name " . $a[1] . " " . $a[2];
  341. if ( $state eq "on" || $ignoreState ne "0" ) {
  342. if ( lc( $a[2] ) eq "true"
  343. || lc( $a[2] ) eq "1"
  344. || lc( $a[2] ) eq "on" )
  345. {
  346. $cmd = "enable=true";
  347. }
  348. elsif (lc( $a[2] ) eq "false"
  349. || lc( $a[2] ) eq "0"
  350. || lc( $a[2] ) eq "off" )
  351. {
  352. $cmd = "enable=false";
  353. }
  354. else {
  355. return "Argument needs to be one of true,1,on,false,0,off";
  356. }
  357. $result = ENIGMA2_SendCommand( $hash, "downmix", $cmd );
  358. }
  359. else {
  360. return "Device needs to be ON to change downmix.";
  361. }
  362. }
  363. # volume
  364. elsif ( lc( $a[1] ) eq "volume" ) {
  365. return "No argument given" if ( !defined( $a[2] ) );
  366. Log3 $name, 3, "ENIGMA2 set $name " . $a[1] . " " . $a[2];
  367. if ( $state eq "on" || $ignoreState ne "0" ) {
  368. if ( $a[2] =~ m/^\d+$/ && $a[2] >= 0 && $a[2] <= 100 ) {
  369. $cmd = "set=set" . $a[2];
  370. }
  371. else {
  372. return
  373. "Argument does not seem to be a valid integer between 0 and 100";
  374. }
  375. $result = ENIGMA2_SendCommand( $hash, "vol", $cmd );
  376. }
  377. else {
  378. return "Device needs to be ON to adjust volume.";
  379. }
  380. }
  381. # volumeUp/volumeDown
  382. elsif ( lc( $a[1] ) =~ /^(volumeup|volumedown)$/ ) {
  383. if ( $state eq "on" || $ignoreState ne "0" ) {
  384. Log3 $name, 3, "ENIGMA2 set $name " . $a[1];
  385. if ( lc( $a[1] ) eq "volumeup" ) {
  386. $cmd = "set=up";
  387. }
  388. else {
  389. $cmd = "set=down";
  390. }
  391. $result = ENIGMA2_SendCommand( $hash, "vol", $cmd );
  392. }
  393. else {
  394. return "Device needs to be ON to adjust volume.";
  395. }
  396. }
  397. # mute
  398. elsif ( lc( $a[1] ) eq "mute" || lc( $a[1] ) eq "mutet" ) {
  399. if ( $state eq "on" || $ignoreState ne "0" ) {
  400. if ( defined( $a[2] ) ) {
  401. Log3 $name, 3, "ENIGMA2 set $name " . $a[1] . " " . $a[2];
  402. }
  403. else {
  404. Log3 $name, 3, "ENIGMA2 set $name " . $a[1];
  405. }
  406. if ( !defined( $a[2] ) || $a[2] eq "toggle" ) {
  407. $cmd = "set=mute";
  408. }
  409. elsif ( lc( $a[2] ) eq "off" ) {
  410. if ( ReadingsVal( $name, "mute", "" ) ne "off" ) {
  411. $cmd = "set=mute";
  412. }
  413. }
  414. elsif ( lc( $a[2] ) eq "on" ) {
  415. if ( ReadingsVal( $name, "mute", "" ) ne "on" ) {
  416. $cmd = "set=mute";
  417. }
  418. }
  419. else {
  420. return "Unknown argument " . $a[2];
  421. }
  422. $result = ENIGMA2_SendCommand( $hash, "vol", $cmd )
  423. if ( $cmd ne "" );
  424. }
  425. else {
  426. return "Device needs to be ON to mute/unmute audio.";
  427. }
  428. }
  429. # msg
  430. elsif ( lc( $a[1] ) eq "msg" ) {
  431. if ( $state ne "absent" || $ignoreState ne "0" ) {
  432. return
  433. "No 1st argument given, choose one of yesno info message attention "
  434. if ( !defined( $a[2] ) );
  435. return "No 2nd argument given, choose one of timeout "
  436. if ( !defined( $a[3] ) );
  437. return "No 3nd argument given, choose one of messagetext "
  438. if ( !defined( $a[4] ) );
  439. return
  440. "Argument "
  441. . $a[3]
  442. . " is not a valid integer between 0 and 49680"
  443. if ( $a[3] !~ m/^\d+$/ || $a[3] < 0 || $a[3] > 49680 );
  444. Log3 $name, 3, "ENIGMA2 set $name " . $a[1] . " " . $a[2];
  445. my $i = 4;
  446. my $text = $a[$i];
  447. $i++;
  448. if ( defined( $a[$i] ) ) {
  449. my $arr_size = @a;
  450. while ( $i < $arr_size ) {
  451. $text = $text . " " . $a[$i];
  452. $i++;
  453. }
  454. }
  455. if ( lc( $a[2] ) eq "yesno" ) {
  456. $cmd = "type=0&timeout=" . $a[3] . "&text=" . urlEncode($text);
  457. }
  458. elsif ( lc( $a[2] ) eq "info" ) {
  459. $cmd = "type=1&timeout=" . $a[3] . "&text=" . urlEncode($text);
  460. }
  461. elsif ( lc( $a[2] ) eq "message" ) {
  462. $cmd = "type=2&timeout=" . $a[3] . "&text=" . urlEncode($text);
  463. }
  464. elsif ( lc( $a[2] ) eq "attention" ) {
  465. $cmd = "type=3&timeout=" . $a[3] . "&text=" . urlEncode($text);
  466. }
  467. else {
  468. return
  469. "Unknown argument "
  470. . $a[2]
  471. . ", choose one of yesno info message attention ";
  472. }
  473. $result = ENIGMA2_SendCommand( $hash, "message", $cmd );
  474. }
  475. else {
  476. return "Device needs to be reachable to send a message to screen.";
  477. }
  478. }
  479. # remoteControl
  480. elsif ( lc( $a[1] ) eq "remotecontrol" ) {
  481. if ( $state ne "absent" || $ignoreState ne "0" ) {
  482. Log3 $name, 3, "ENIGMA2 set $name " . $a[1] . " " . $a[2]
  483. if !defined( $a[3] );
  484. Log3 $name, 3,
  485. "ENIGMA2 set $name " . $a[1] . " " . $a[2] . " " . $a[3]
  486. if defined( $a[3] );
  487. my $commandKeys = join(
  488. " ",
  489. keys %{
  490. ENIGMA2_GetRemotecontrolCommand("GetRemotecontrolCommands")
  491. }
  492. );
  493. if ( !defined( $a[2] ) ) {
  494. return "No argument given, choose one of " . $commandKeys;
  495. }
  496. my $request = ENIGMA2_GetRemotecontrolCommand( uc( $a[2] ) );
  497. $request = $a[2]
  498. if ( $request eq "" && $a[2] =~ /^\d+$/ );
  499. if ( uc( $a[2] ) eq "POWER" ) {
  500. return ENIGMA2_Set( $hash, $name, "toggle" );
  501. }
  502. elsif ( uc( $a[2] ) eq "MUTE" ) {
  503. return ENIGMA2_Set( $hash, $name, "mute" );
  504. }
  505. elsif ( $request ne "" ) {
  506. $cmd = "command=" . $request;
  507. $cmd .= "&rcu=" . AttrVal( $name, "remotecontrol", "" )
  508. if ( AttrVal( $name, "remotecontrol", "" ) ne "" );
  509. $cmd .= "&type=long"
  510. if ( defined( $a[3] ) && lc( $a[3] ) eq "long" );
  511. }
  512. else {
  513. return
  514. "Unknown argument "
  515. . $a[2]
  516. . ", choose one of "
  517. . $commandKeys;
  518. }
  519. $result = ENIGMA2_SendCommand( $hash, "remotecontrol", $cmd );
  520. }
  521. else {
  522. return "Device needs to be reachable to be controlled remotely.";
  523. }
  524. }
  525. # channel
  526. elsif ( lc( $a[1] ) eq "channel" ) {
  527. return
  528. "No argument given, choose one of channel channelNumber servicereference "
  529. if ( !defined( $a[2] ) );
  530. if ( defined( $a[2] )
  531. && $presence eq "present"
  532. && $state ne "on" )
  533. {
  534. Log3 $name, 4, "ENIGMA2 $name: indirect switching request to ON";
  535. ENIGMA2_Set( $hash, $name, "on" );
  536. }
  537. Log3 $name, 3, "ENIGMA2 set $name " . $a[1] . " " . $a[2];
  538. if ( $state eq "on" || $ignoreState ne "0" ) {
  539. my $cname = $a[2];
  540. if ( defined( $hash->{helper}{bouquet}{$input}{$cname}{sRef} ) ) {
  541. $result = ENIGMA2_SendCommand(
  542. $hash, "zap",
  543. "sRef="
  544. . urlEncode(
  545. $hash->{helper}{bouquet}{$input}{$cname}{sRef}
  546. )
  547. );
  548. }
  549. elsif ( $cname =~ m/^(\d+):(.*):$/ ) {
  550. $result =
  551. ENIGMA2_SendCommand( $hash, "zap",
  552. "sRef=" . urlEncode($cname) );
  553. }
  554. elsif ( $cname =~ m/^\d+$/ && $cname > 0 && $cname < 10000 ) {
  555. for ( split( //, $a[2] ) ) {
  556. $cmd = "command=" . ENIGMA2_GetRemotecontrolCommand($cname);
  557. $result =
  558. ENIGMA2_SendCommand( $hash, "remotecontrol", $cmd );
  559. }
  560. $result = ENIGMA2_SendCommand( $hash, "remotecontrol",
  561. "command=" . ENIGMA2_GetRemotecontrolCommand("OK") );
  562. }
  563. elsif ( m/^\d+$/ && ( $cname <= 0 || $cname >= 10000 ) ) {
  564. return "Numeric channel addressing '" . $cname
  565. . "' needs to be a number between 1 and 9999.";
  566. }
  567. else {
  568. return
  569. "'"
  570. . $cname
  571. . "' does not seem to be a valid channel. Known channels: "
  572. . $channels;
  573. }
  574. }
  575. else {
  576. return
  577. "Device needs to be present to switch to a specific channel.";
  578. }
  579. }
  580. # channelUp/channelDown
  581. elsif ( lc( $a[1] ) =~ /^(channelup|channeldown)$/ ) {
  582. Log3 $name, 3, "ENIGMA2 set $name " . $a[1];
  583. if ( $state eq "on" || $ignoreState ne "0" ) {
  584. if ( lc( $a[1] ) eq "channelup" ) {
  585. $cmd = "command=" . ENIGMA2_GetRemotecontrolCommand("RIGHT");
  586. }
  587. else {
  588. $cmd = "command=" . ENIGMA2_GetRemotecontrolCommand("LEFT");
  589. }
  590. $result = ENIGMA2_SendCommand( $hash, "remotecontrol", $cmd );
  591. }
  592. else {
  593. return "Device needs to be ON to switch channel.";
  594. }
  595. }
  596. # input
  597. elsif ( lc( $a[1] ) eq "input" ) {
  598. return "No argument given, choose one of tv radio "
  599. if ( !defined( $a[2] ) );
  600. if ( defined( $a[2] )
  601. && $presence eq "present"
  602. && $state ne "on" )
  603. {
  604. Log3 $name, 4, "ENIGMA2 $name: indirect switching request to ON";
  605. ENIGMA2_Set( $hash, $name, "on" );
  606. }
  607. Log3 $name, 3, "ENIGMA2 set $name " . $a[1] . " " . $a[2];
  608. if ( $state eq "on" || $ignoreState ne "0" ) {
  609. if ( lc( $a[2] ) eq "tv" ) {
  610. $cmd = "command=" . ENIGMA2_GetRemotecontrolCommand("TV");
  611. }
  612. elsif ( lc( $a[2] ) eq "radio" ) {
  613. $cmd = "command=" . ENIGMA2_GetRemotecontrolCommand("RADIO");
  614. }
  615. else {
  616. return
  617. "Argument "
  618. . $a[2]
  619. . " is not valid, please choose one from tv radio ";
  620. }
  621. $result = ENIGMA2_SendCommand( $hash, "remotecontrol", $cmd );
  622. }
  623. else {
  624. return "Device needs to be present to switch input.";
  625. }
  626. }
  627. # play / pause
  628. elsif ( lc( $a[1] ) =~ /^(play|pause)$/ ) {
  629. if ( $state eq "on" || $ignoreState ne "0" ) {
  630. Log3 $name, 3, "ENIGMA2 set $name " . $a[1];
  631. $cmd = "command=" . ENIGMA2_GetRemotecontrolCommand("PLAYPAUSE");
  632. $result = ENIGMA2_SendCommand( $hash, "remotecontrol", $cmd );
  633. }
  634. else {
  635. return "Device needs to be ON to play or pause video.";
  636. }
  637. }
  638. # stop
  639. elsif ( lc( $a[1] ) eq "stop" ) {
  640. if ( $state eq "on" || $ignoreState ne "0" ) {
  641. Log3 $name, 3, "ENIGMA2 set $name " . $a[1];
  642. $cmd = "command=" . ENIGMA2_GetRemotecontrolCommand("STOP");
  643. $result = ENIGMA2_SendCommand( $hash, "remotecontrol", $cmd );
  644. }
  645. else {
  646. return "Device needs to be ON to stop video.";
  647. }
  648. }
  649. # record
  650. elsif ( lc( $a[1] ) eq "record" ) {
  651. if ( $state eq "on" || $ignoreState ne "0" ) {
  652. Log3 $name, 3, "ENIGMA2 set $name " . $a[1];
  653. $result = ENIGMA2_SendCommand( $hash, "recordnow" );
  654. }
  655. else {
  656. return "Device needs to be ON to start instant recording.";
  657. }
  658. }
  659. # showText
  660. elsif ( lc( $a[1] ) eq "showtext" ) {
  661. if ( $state ne "absent" || $ignoreState ne "0" ) {
  662. return "No argument given, choose one of messagetext "
  663. if ( !defined( $a[2] ) );
  664. Log3 $name, 3, "ENIGMA2 set $name " . $a[1];
  665. my $i = 2;
  666. my $text = $a[$i];
  667. $i++;
  668. if ( defined( $a[$i] ) ) {
  669. my $arr_size = @a;
  670. while ( $i < $arr_size ) {
  671. $text = $text . " " . $a[$i];
  672. $i++;
  673. }
  674. }
  675. $cmd = "type=1&timeout=8&text=" . urlEncode($text);
  676. $result = ENIGMA2_SendCommand( $hash, "message", $cmd );
  677. }
  678. else {
  679. return "Device needs to be reachable to send a message to screen.";
  680. }
  681. }
  682. # return usage hint
  683. else {
  684. return $usage;
  685. }
  686. return;
  687. }
  688. ###################################
  689. sub ENIGMA2_Define($$) {
  690. my ( $hash, $def ) = @_;
  691. my @a = split( "[ \t][ \t]*", $def );
  692. my $name = $hash->{NAME};
  693. Log3 $name, 5, "ENIGMA2 $name: called function ENIGMA2_Define()";
  694. eval { require XML::Simple; };
  695. return "Please install Perl XML::Simple to use module ENIGMA2"
  696. if ($@);
  697. if ( int(@a) < 3 ) {
  698. my $msg =
  699. "Wrong syntax: define <name> ENIGMA2 <ip-or-hostname> [[[[<port>] [<poll-interval>]] [<http-user]] [<http-password>]]";
  700. Log3 $name, 4, $msg;
  701. return $msg;
  702. }
  703. $hash->{TYPE} = "ENIGMA2";
  704. my $address = $a[2];
  705. $hash->{helper}{ADDRESS} = $address;
  706. # use port 80 if not defined
  707. my $port = $a[3] || 80;
  708. return "Port parameter needs to be of type integer" if ( $port !~ /^\d+$/ );
  709. $hash->{helper}{PORT} = $port;
  710. # use interval of 45sec if not defined
  711. my $interval = $a[4] || 45;
  712. return "Interval parameter needs to be of type integer"
  713. if ( $interval !~ /^\d+$/ );
  714. $hash->{INTERVAL} = $interval;
  715. # set http user if defined
  716. my $http_user = $a[5];
  717. $hash->{helper}{USER} = $http_user if $http_user;
  718. # set http password if defined
  719. my $http_passwd = $a[6];
  720. $hash->{helper}{PASSWORD} = $http_passwd if $http_passwd;
  721. # set default settings on first define
  722. if ( $init_done && !defined( $hash->{OLDDEF} ) ) {
  723. # use http-method POST for FritzBox environment as GET does not seem to
  724. # work properly. Might restrict use to newer
  725. # ENIGMA2 Webif versions or use of OWIF only.
  726. if ( exists $ENV{CONFIG_PRODUKT_NAME}
  727. && defined $ENV{CONFIG_PRODUKT_NAME} )
  728. {
  729. $attr{$name}{"http-method"} = 'POST';
  730. }
  731. # default method is GET and should be compatible to most
  732. # ENIGMA2 Webif versions
  733. else {
  734. $attr{$name}{"http-method"} = 'GET';
  735. }
  736. $attr{$name}{webCmd} = 'channel:input';
  737. $attr{$name}{devStateIcon} =
  738. 'on:rc_GREEN:off off:rc_YELLOW:on absent:rc_STOP:on';
  739. $attr{$name}{icon} = 'dreambox';
  740. }
  741. # start the status update timer
  742. RemoveInternalTimer($hash);
  743. InternalTimer( gettimeofday() + 2, "ENIGMA2_GetStatus", $hash, 1 );
  744. return;
  745. }
  746. ############################################################################################################
  747. #
  748. # Begin of helper functions
  749. #
  750. ############################################################################################################
  751. ###################################
  752. sub ENIGMA2_SendCommand($$;$$) {
  753. my ( $hash, $service, $cmd, $type ) = @_;
  754. my $name = $hash->{NAME};
  755. my $address = $hash->{helper}{ADDRESS};
  756. my $port = $hash->{helper}{PORT};
  757. my $http_method = AttrVal( $name, "http-method", "GET" );
  758. my $http_noshutdown = AttrVal( $name, "http-noshutdown", "1" );
  759. my $timeout;
  760. $cmd = ( defined($cmd) ) ? $cmd : "";
  761. Log3 $name, 5, "ENIGMA2 $name: called function ENIGMA2_SendCommand()";
  762. my $http_proto;
  763. if ( $port eq "443" ) {
  764. $http_proto = "https";
  765. Log3 $name, 5, "ENIGMA2 $name: port 443 implies using HTTPS";
  766. }
  767. elsif ( AttrVal( $name, "https", "0" ) eq "1" ) {
  768. Log3 $name, 5, "ENIGMA2 $name: explicit use of HTTPS";
  769. $http_proto = "https";
  770. if ( $port eq "80" ) {
  771. $port = "443";
  772. Log3 $name, 5,
  773. "ENIGMA2 $name: implicit change of from port 80 to 443";
  774. }
  775. }
  776. else {
  777. Log3 $name, 5, "ENIGMA2 $name: using unencrypted connection via HTTP";
  778. $http_proto = "http";
  779. }
  780. my $http_user = "";
  781. my $http_passwd = "";
  782. if ( defined( $hash->{helper}{USER} )
  783. && defined( $hash->{helper}{PASSWORD} ) )
  784. {
  785. Log3 $name, 5, "ENIGMA2 $name: using BasicAuth";
  786. $http_user = $hash->{helper}{USER};
  787. $http_passwd = $hash->{helper}{PASSWORD};
  788. }
  789. if ( defined( $hash->{helper}{USER} ) ) {
  790. Log3 $name, 5, "ENIGMA2 $name: using BasicAuth (username only)";
  791. $http_user = $hash->{helper}{USER};
  792. }
  793. my $URL;
  794. my $response;
  795. my $return;
  796. if ( !defined($cmd) || $cmd eq "" ) {
  797. Log3 $name, 4, "ENIGMA2 $name: REQ $service";
  798. }
  799. else {
  800. $cmd = "?" . $cmd . "&"
  801. if ( $http_method eq "GET" || $http_method eq "" );
  802. Log3 $name, 4, "ENIGMA2 $name: REQ $service/" . urlDecode($cmd);
  803. }
  804. if ( $http_user ne "" && $http_passwd ne "" ) {
  805. $URL =
  806. $http_proto . "://"
  807. . $http_user . ":"
  808. . $http_passwd . "@"
  809. . $address . ":"
  810. . $port . "/web/"
  811. . $service;
  812. $URL .= $cmd if ( $http_method eq "GET" || $http_method eq "" );
  813. }
  814. elsif ( $http_user ne "" ) {
  815. $URL =
  816. $http_proto . "://"
  817. . $http_user . "@"
  818. . $address . ":"
  819. . $port . "/web/"
  820. . $service;
  821. $URL .= $cmd if ( $http_method eq "GET" || $http_method eq "" );
  822. }
  823. else {
  824. $URL =
  825. $http_proto . "://" . $address . ":" . $port . "/web/" . $service;
  826. $URL .= $cmd if ( $http_method eq "GET" || $http_method eq "" );
  827. }
  828. if ( AttrVal( $name, "timeout", "3" ) =~ /^\d+$/ ) {
  829. $timeout = AttrVal( $name, "timeout", "3" );
  830. }
  831. else {
  832. Log3 $name, 3, "ENIGMA2 $name: wrong format in attribute 'timeout'";
  833. $timeout = 3;
  834. }
  835. # send request via HTTP-GET method
  836. if ( $http_method eq "GET" || $http_method eq "" || $cmd eq "" ) {
  837. Log3 $name, 5,
  838. "ENIGMA2 $name: GET "
  839. . urlDecode($URL)
  840. . " (noshutdown="
  841. . $http_noshutdown . ")";
  842. HttpUtils_NonblockingGet(
  843. {
  844. url => $URL,
  845. timeout => $timeout,
  846. noshutdown => $http_noshutdown,
  847. data => undef,
  848. hash => $hash,
  849. service => $service,
  850. cmd => $cmd,
  851. type => $type,
  852. callback => \&ENIGMA2_ReceiveCommand,
  853. httpversion => "1.1",
  854. }
  855. );
  856. }
  857. # send request via HTTP-POST method
  858. elsif ( $http_method eq "POST" ) {
  859. Log3 $name, 5,
  860. "ENIGMA2 $name: GET "
  861. . $URL
  862. . " (POST DATA: "
  863. . urlDecode($cmd)
  864. . ", noshutdown="
  865. . $http_noshutdown . ")";
  866. HttpUtils_NonblockingGet(
  867. {
  868. url => $URL,
  869. timeout => $timeout,
  870. noshutdown => $http_noshutdown,
  871. data => $cmd,
  872. hash => $hash,
  873. service => $service,
  874. cmd => $cmd,
  875. type => $type,
  876. callback => \&ENIGMA2_ReceiveCommand,
  877. }
  878. );
  879. }
  880. # other HTTP methods are not supported
  881. else {
  882. Log3 $name, 1,
  883. "ENIGMA2 $name: ERROR: HTTP method "
  884. . $http_method
  885. . " is not supported.";
  886. }
  887. return;
  888. }
  889. ###################################
  890. sub ENIGMA2_ReceiveCommand($$$) {
  891. my ( $param, $err, $data ) = @_;
  892. my $hash = $param->{hash};
  893. my $name = $hash->{NAME};
  894. my $service = $param->{service};
  895. my $cmd = $param->{cmd};
  896. my $state = ReadingsVal( $name, "state", "off" );
  897. my $presence = ReadingsVal( $name, "presence", "absent" );
  898. my $type = ( $param->{type} ) ? $param->{type} : "";
  899. my $return;
  900. Log3 $name, 5, "ENIGMA2 $name: called function ENIGMA2_ReceiveCommand()";
  901. readingsBeginUpdate($hash);
  902. # device not reachable
  903. if ($err) {
  904. # powerstate
  905. if ( $service eq "powerstate" ) {
  906. $state = "absent";
  907. if ( !defined($cmd) || $cmd eq "" ) {
  908. Log3 $name, 4, "ENIGMA2 $name: RCV TIMEOUT $service";
  909. }
  910. else {
  911. Log3 $name, 4,
  912. "ENIGMA2 $name: RCV TIMEOUT $service/" . urlDecode($cmd);
  913. }
  914. $presence = "absent";
  915. readingsBulkUpdateIfChanged( $hash, "presence", $presence );
  916. }
  917. }
  918. # data received
  919. elsif ($data) {
  920. $presence = "present";
  921. readingsBulkUpdateIfChanged( $hash, "presence", $presence );
  922. if ( !defined($cmd) || $cmd eq "" ) {
  923. Log3 $name, 4, "ENIGMA2 $name: RCV $service";
  924. }
  925. else {
  926. Log3 $name, 4, "ENIGMA2 $name: RCV $service/" . urlDecode($cmd);
  927. }
  928. if ( $data ne "" ) {
  929. if ( $data =~ /^<\?xml/ && $data !~ /<\/html>/ ) {
  930. if ( !defined($cmd) || $cmd eq "" ) {
  931. Log3 $name, 5, "ENIGMA2 $name: RES $service\n" . $data;
  932. }
  933. else {
  934. Log3 $name, 5,
  935. "ENIGMA2 $name: RES $service/"
  936. . urlDecode($cmd) . "\n"
  937. . $data;
  938. }
  939. my $parser = XML::Simple->new(
  940. NormaliseSpace => 2,
  941. KeepRoot => 0,
  942. ForceArray => 0,
  943. SuppressEmpty => 1,
  944. KeyAttr => {}
  945. );
  946. eval
  947. '$return = $parser->XMLin( Encode::encode_utf8($data) ); 1';
  948. if ($@) {
  949. if ( !defined($cmd) || $cmd eq "" ) {
  950. Log3 $name, 5,
  951. "ENIGMA2 $name: RES ERROR $service - unable to parse malformed XML: $@\n"
  952. . $data;
  953. }
  954. else {
  955. Log3 $name, 5,
  956. "ENIGMA2 $name: RES ERROR $service/"
  957. . urlDecode($cmd)
  958. . " - unable to parse malformed XML: $@\n"
  959. . $data;
  960. }
  961. return undef;
  962. }
  963. undef $parser;
  964. }
  965. else {
  966. if ( !defined($cmd) || $cmd eq "" ) {
  967. Log3 $name, 5,
  968. "ENIGMA2 $name: RES ERROR $service - not in XML format\n"
  969. . $data;
  970. }
  971. else {
  972. Log3 $name, 5,
  973. "ENIGMA2 $name: RES ERROR $service/"
  974. . urlDecode($cmd)
  975. . " - not in XML format\n"
  976. . $data;
  977. }
  978. return undef;
  979. }
  980. }
  981. $return = Encode::encode_utf8($data)
  982. if ( $return && ref($return) ne "HASH" );
  983. #######################
  984. # process return data
  985. #
  986. # powerstate
  987. if ( $service eq "powerstate" ) {
  988. if ( defined($return)
  989. && ref($return) eq "HASH" )
  990. {
  991. # Cache bouquet information - get favorite bouquet
  992. # if not available from helper
  993. if (
  994. !defined($type)
  995. || ( $type ne "shutdown"
  996. && $type ne "reboot"
  997. && $type ne "restartGui"
  998. && $type ne "off" )
  999. )
  1000. {
  1001. foreach my $input ( "tv", "radio" ) {
  1002. if ( !defined( $hash->{helper}{bouquet}{$input} )
  1003. || !defined( $hash->{helper}{channels}{$input} ) )
  1004. {
  1005. my $service_uri =
  1006. '1:7:2:0:0:0:0:0:0:0:(type == 2)FROM BOUQUET "bouquets.'
  1007. . $input
  1008. . '" ORDER BY bouquet';
  1009. # trigger cache update
  1010. if (
  1011. AttrVal( $name, "bouquet-" . $input, "" ) ne
  1012. "" )
  1013. {
  1014. ENIGMA2_SendCommand(
  1015. $hash,
  1016. "getservices",
  1017. "sRef="
  1018. . urlEncode(
  1019. AttrVal(
  1020. $name, "bouquet-" . $input, ""
  1021. )
  1022. ),
  1023. "services-" . $input
  1024. );
  1025. }
  1026. # set attributes first
  1027. else {
  1028. ENIGMA2_SendCommand(
  1029. $hash, "getservices",
  1030. "sRef=" . urlEncode($service_uri),
  1031. "defBouquet-" . $input
  1032. );
  1033. }
  1034. }
  1035. }
  1036. }
  1037. if ( $type eq "shutdown"
  1038. || $type eq "reboot"
  1039. || $type eq "restartGui"
  1040. || $type eq "off"
  1041. || ( $return->{e2instandby} eq "true" && $type ne "on" ) )
  1042. {
  1043. $state = "off";
  1044. # Keep updating some information during standby
  1045. if ( !AttrVal( $name, "lightMode", 0 ) ) {
  1046. ENIGMA2_SendCommand( $hash, "timerlist" );
  1047. # Read Boxinfo every 15 minutes only
  1048. if (
  1049. !defined( $hash->{helper}{lastFullUpdate} )
  1050. || ( defined( $hash->{helper}{lastFullUpdate} )
  1051. && $hash->{helper}{lastFullUpdate} +
  1052. 900 le time() )
  1053. )
  1054. {
  1055. ENIGMA2_SendCommand( $hash, "about" );
  1056. # Update state
  1057. $hash->{helper}{lastFullUpdate} = time();
  1058. }
  1059. }
  1060. }
  1061. else {
  1062. $state = "on";
  1063. # Read Boxinfo every 15 minutes only
  1064. if (
  1065. !defined( $hash->{helper}{lastFullUpdate} )
  1066. || ( defined( $hash->{helper}{lastFullUpdate} )
  1067. && $hash->{helper}{lastFullUpdate} + 900 le time() )
  1068. )
  1069. {
  1070. ENIGMA2_SendCommand( $hash, "about" );
  1071. # Update state
  1072. $hash->{helper}{lastFullUpdate} = time();
  1073. }
  1074. # get current states
  1075. ENIGMA2_SendCommand( $hash, "getcurrent" );
  1076. ENIGMA2_SendCommand( $hash, "timerlist" )
  1077. if ( !AttrVal( $name, "lightMode", 0 ) );
  1078. ENIGMA2_SendCommand( $hash, "vol" )
  1079. if ( !AttrVal( $name, "lightMode", 0 ) );
  1080. ENIGMA2_SendCommand( $hash, "signal" )
  1081. if ( !AttrVal( $name, "lightMode", 0 ) );
  1082. }
  1083. }
  1084. elsif ( $state ne "undefined" ) {
  1085. Log3 $name, 2,
  1086. "ENIGMA2 $name: ERROR: Undefined state of device";
  1087. $state = "undefined";
  1088. }
  1089. }
  1090. # update attributes for bouquet names
  1091. elsif ( $service eq "getservices"
  1092. && ( $type eq "defBouquet-tv" || $type eq "defBouquet-radio" ) )
  1093. {
  1094. my $input = ( $type eq "defBouquet-tv" ) ? "tv" : "radio";
  1095. # set FHEM device attribute if not available
  1096. # multiple
  1097. if ( ref($return) eq "HASH"
  1098. && defined( $return->{e2service} )
  1099. && ref( $return->{e2service} ) eq "ARRAY"
  1100. && defined( $return->{e2service}[0]{e2servicereference} )
  1101. && $return->{e2service}[0]{e2servicereference} ne "" )
  1102. {
  1103. Log3 $name, 3,
  1104. "ENIGMA2 $name: Adding attribute bouquet-"
  1105. . $input . " = "
  1106. . $return->{e2service}[0]{e2servicereference};
  1107. $attr{$name}{ "bouquet-" . $input } =
  1108. $return->{e2service}[0]{e2servicereference};
  1109. }
  1110. # single
  1111. elsif (ref($return) eq "HASH"
  1112. && defined( $return->{e2service}{e2servicereference} )
  1113. && $return->{e2service}{e2servicereference} ne "" )
  1114. {
  1115. Log3 $name, 3,
  1116. "ENIGMA2 $name: Adding attribute bouquet-"
  1117. . $input . " = "
  1118. . $return->{e2service}{e2servicereference};
  1119. $attr{$name}{ "bouquet-" . $input } =
  1120. $return->{e2service}{e2servicereference};
  1121. }
  1122. elsif ( AttrVal( $name, "bouquet-" . $input, "" ) eq "" ) {
  1123. Log3 $name, 3,
  1124. "ENIGMA2 $name: ERROR: Unable to read any "
  1125. . $input
  1126. . " bouquets from device";
  1127. }
  1128. # trigger cache update
  1129. ENIGMA2_SendCommand(
  1130. $hash,
  1131. "getservices",
  1132. "sRef="
  1133. . urlEncode( AttrVal( $name, "bouquet-" . $input, "" ) ),
  1134. "services-" . $input
  1135. ) if ( AttrVal( $name, "bouquet-" . $input, "" ) ne "" );
  1136. }
  1137. # update cache of tv and radio channels
  1138. elsif ( $service eq "getservices"
  1139. && ( $type eq "services-tv" || $type eq "services-radio" ) )
  1140. {
  1141. my $input = ( $type eq "services-tv" ) ? "tv" : "radio";
  1142. # Read channels
  1143. if ( ref($return) eq "HASH"
  1144. && defined( $return->{e2service} ) )
  1145. {
  1146. # multiple
  1147. if ( ref( $return->{e2service} ) eq "ARRAY"
  1148. && defined( $return->{e2service}[0]{e2servicename} )
  1149. && $return->{e2service}[0]{e2servicename} ne ""
  1150. && defined( $return->{e2service}[0]{e2servicereference} )
  1151. && $return->{e2service}[0]{e2servicereference} ne "" )
  1152. {
  1153. my $i = 0;
  1154. foreach my $key ( keys @{ $return->{e2service} } ) {
  1155. my $channel =
  1156. $return->{e2service}[$key]{e2servicename};
  1157. $channel =~ s/\s/_/g;
  1158. # ignore markers
  1159. if ( $return->{e2service}[$key]{e2servicereference} =~
  1160. /^1:64:/ )
  1161. {
  1162. Log3 $name, 4,
  1163. "ENIGMA2 $name: Ignoring marker "
  1164. . $return->{e2service}[$key]{e2servicename};
  1165. next;
  1166. }
  1167. if ( $channel ne "" ) {
  1168. $hash->{helper}{bouquet}{$input}{$channel} =
  1169. { 'sRef' =>
  1170. $return->{e2service}[$key]{e2servicereference}
  1171. };
  1172. $hash->{helper}{channels}{$input}[$i] =
  1173. $channel;
  1174. }
  1175. $i++;
  1176. }
  1177. Log3 $name, 4,
  1178. "ENIGMA2 $name: Cached favorite "
  1179. . $input
  1180. . " channels: "
  1181. . join( ', ', @{ $hash->{helper}{channels}{$input} } );
  1182. }
  1183. # single
  1184. elsif (defined( $return->{e2service}{e2servicename} )
  1185. && $return->{e2service}{e2servicename} ne ""
  1186. && defined( $return->{e2service}{e2servicereference} )
  1187. && $return->{e2service}{e2servicereference} ne "" )
  1188. {
  1189. # ignore markers
  1190. if ( $return->{e2service}{e2servicereference} =~ /^1:64:/ )
  1191. {
  1192. Log3 $name, 4,
  1193. "ENIGMA2 $name: Ignoring marker "
  1194. . $return->{e2service}{e2servicename};
  1195. }
  1196. else {
  1197. my $channel = $return->{e2service}{e2servicename};
  1198. $channel =~ s/\s/_/g;
  1199. if ( $channel ne "" ) {
  1200. $hash->{helper}{bouquet}{$input}{$channel} =
  1201. { 'sRef' =>
  1202. $return->{e2service}{e2servicereference} };
  1203. $hash->{helper}{channels}{$input}[0] =
  1204. $channel;
  1205. Log3 $name, 4,
  1206. "ENIGMA2 $name: Cached favorite "
  1207. . $input
  1208. . " channels: "
  1209. . $hash->{helper}{channels}{$input}[0];
  1210. }
  1211. }
  1212. }
  1213. else {
  1214. Log3 $name, 4,
  1215. "ENIGMA2 $name: ERROR: bouquet-"
  1216. . $input
  1217. . " seems to be empty.";
  1218. }
  1219. }
  1220. elsif ( $input eq "radio" ) {
  1221. Log3 $name, 4,
  1222. "ENIGMA2 $name: ERROR: Unable to read "
  1223. . $input
  1224. . " bouquet '"
  1225. . AttrVal( $name, "bouquet-" . $input, "" )
  1226. . "' from device";
  1227. }
  1228. else {
  1229. Log3 $name, 3,
  1230. "ENIGMA2 $name: ERROR: Unable to read "
  1231. . $input
  1232. . " bouquet '"
  1233. . AttrVal( $name, "bouquet-" . $input, "" )
  1234. . "' from device";
  1235. }
  1236. }
  1237. # boxinfo
  1238. elsif ( $service eq "about" ) {
  1239. my $reading;
  1240. my $e2reading;
  1241. if ( ref($return) eq "HASH" ) {
  1242. # General readings
  1243. foreach my $reading (
  1244. "enigmaversion", "imageversion",
  1245. "webifversion", "fpversion",
  1246. "lanmac", "model",
  1247. )
  1248. {
  1249. $e2reading = "e2" . $reading;
  1250. if ( defined( $return->{e2about}{$e2reading} ) ) {
  1251. if ( $return->{e2about}{$e2reading} eq "False"
  1252. || $return->{e2about}{$e2reading} eq "True" )
  1253. {
  1254. readingsBulkUpdateIfChanged( $hash, $reading,
  1255. lc( $return->{e2about}{$e2reading} ) );
  1256. }
  1257. else {
  1258. readingsBulkUpdateIfChanged( $hash, $reading,
  1259. $return->{e2about}{$e2reading} );
  1260. }
  1261. # model
  1262. if ( $reading eq "model"
  1263. && ReadingsVal( $name, "model", "" ) ne "" )
  1264. {
  1265. my $model = ReadingsVal( $name, "model", "" );
  1266. $model =~ s/\s/_/g;
  1267. $hash->{modelid} = uc($model);
  1268. $attr{$name}{model} = uc($model);
  1269. }
  1270. }
  1271. else {
  1272. readingsBulkUpdateIfChanged( $hash, $reading, "-" );
  1273. }
  1274. }
  1275. # HDD
  1276. if ( defined( $return->{e2about}{e2hddinfo} ) ) {
  1277. # multiple
  1278. if ( ref( $return->{e2about}{e2hddinfo} ) eq "ARRAY" ) {
  1279. Log3 $name, 5, "ENIGMA2 $name: multiple HDDs detected";
  1280. my $i = 0;
  1281. my $arr_size = @{ $return->{e2about}{e2hddinfo} };
  1282. while ( $i < $arr_size ) {
  1283. my $counter = $i + 1;
  1284. my $readingname = "hdd" . $counter . "_model";
  1285. readingsBulkUpdateIfChanged( $hash, $readingname,
  1286. $return->{e2about}{e2hddinfo}[$i]{model} );
  1287. $readingname = "hdd" . $counter . "_capacity";
  1288. my @value =
  1289. split( / /,
  1290. $return->{e2about}{e2hddinfo}[$i]{capacity} );
  1291. readingsBulkUpdate( $hash, $readingname, $value[0] )
  1292. if ( @value
  1293. && ReadingsVal( $name, $readingname, "" ) ne
  1294. $value[0] );
  1295. $readingname = "hdd" . $counter . "_free";
  1296. @value =
  1297. split( / /,
  1298. $return->{e2about}{e2hddinfo}[$i]{free} );
  1299. readingsBulkUpdate( $hash, $readingname, $value[0] )
  1300. if ( @value
  1301. && ReadingsVal( $name, $readingname, "" ) ne
  1302. $value[0] );
  1303. $i++;
  1304. }
  1305. }
  1306. # single
  1307. elsif ( ref( $return->{e2about}{e2hddinfo} ) eq "HASH" ) {
  1308. Log3 $name, 5, "ENIGMA2 $name: single HDD detected";
  1309. my $readingname = "hdd1_model";
  1310. readingsBulkUpdateIfChanged( $hash, $readingname,
  1311. $return->{e2about}{e2hddinfo}{model} );
  1312. $readingname = "hdd1_capacity";
  1313. my @value =
  1314. split( / /, $return->{e2about}{e2hddinfo}{capacity} );
  1315. readingsBulkUpdate( $hash, $readingname, $value[0] )
  1316. if ( @value
  1317. && ReadingsVal( $name, $readingname, "" ) ne
  1318. $value[0] );
  1319. $readingname = "hdd1_free";
  1320. @value =
  1321. split( / /, $return->{e2about}{e2hddinfo}{free} );
  1322. readingsBulkUpdate( $hash, $readingname, $value[0] )
  1323. if ( @value
  1324. && ReadingsVal( $name, $readingname, "" ) ne
  1325. $value[0] );
  1326. }
  1327. else {
  1328. Log3 $name, 5,
  1329. "ENIGMA2 $name: no HDD seems to be installed";
  1330. }
  1331. }
  1332. # Tuner
  1333. if ( defined( $return->{e2about}{e2tunerinfo}{e2nim} ) ) {
  1334. # multiple
  1335. if (
  1336. ref( $return->{e2about}{e2tunerinfo}{e2nim} ) eq
  1337. "ARRAY" )
  1338. {
  1339. Log3 $name, 5,
  1340. "ENIGMA2 $name: multi-tuner configuration detected";
  1341. foreach my $tuner (
  1342. @{ $return->{e2about}{e2tunerinfo}{e2nim} } )
  1343. {
  1344. my $tuner_name = lc( $tuner->{name} );
  1345. $tuner_name =~ s/\s/_/g;
  1346. $tuner_name = "tuner_$tuner_name"
  1347. if ( $tuner_name !~ /^[Tt]uner_/ );
  1348. $tuner_name =~ s/[^A-Za-z\/\d_\.-]//g;
  1349. readingsBulkUpdateIfChanged( $hash, $tuner_name,
  1350. $tuner->{type} );
  1351. }
  1352. }
  1353. # single
  1354. elsif (
  1355. ref( $return->{e2about}{e2tunerinfo}{e2nim} ) eq
  1356. "HASH" )
  1357. {
  1358. Log3 $name, 5,
  1359. "ENIGMA2 $name: single-tuner configuration detected";
  1360. my $tuner_name =
  1361. lc( $return->{e2about}{e2tunerinfo}{e2nim}{name} );
  1362. $tuner_name =~ s/\s/_/g;
  1363. $tuner_name = "tuner_$tuner_name"
  1364. if ( $tuner_name !~ /^[Tt]uner_/ );
  1365. $tuner_name =~ s/[^A-Za-z\/\d_\.-]//g;
  1366. readingsBulkUpdateIfChanged( $hash, $tuner_name,
  1367. $return->{e2about}{e2tunerinfo}{e2nim}{type} );
  1368. }
  1369. else {
  1370. Log3 $name, 5,
  1371. "ENIGMA2 $name: no tuner could be detected";
  1372. }
  1373. }
  1374. }
  1375. else {
  1376. Log3 $name, 2,
  1377. "ENIGMA2 $name: ERROR: boxinfo could not be read - /about sent malformed response";
  1378. }
  1379. }
  1380. # currsrvinfo
  1381. elsif ( $service eq "getcurrent" ) {
  1382. my $reading;
  1383. my $e2reading;
  1384. if ( ref($return) eq "HASH" ) {
  1385. # Service readings
  1386. foreach my $reading (
  1387. "servicereference", "servicename",
  1388. "providername", "servicevideosize",
  1389. "videowidth", "videoheight",
  1390. "iswidescreen", "apid",
  1391. "vpid", "pcrpid",
  1392. "pmtpid", "txtpid",
  1393. "tsid", "onid",
  1394. "sid"
  1395. )
  1396. {
  1397. $e2reading = "e2" . $reading;
  1398. if ( defined( $return->{e2service}{$e2reading} )
  1399. && lc( $return->{e2service}{$e2reading} ) ne "n/a"
  1400. && lc( $return->{e2service}{$e2reading} ) ne "n/axn/a"
  1401. && lc( $return->{e2service}{$e2reading} ) ne "0x0" )
  1402. {
  1403. if ( $return->{e2service}{$e2reading} eq "False"
  1404. || $return->{e2service}{$e2reading} eq "True" )
  1405. {
  1406. Log3 $name, 5,
  1407. "ENIGMA2 $name: transforming value of $reading to lower case";
  1408. $return->{e2service}{$e2reading} =
  1409. lc( $return->{e2service}{$e2reading} );
  1410. }
  1411. if ( ReadingsVal( $name, $reading, "" ) ne
  1412. $return->{e2service}{$e2reading} )
  1413. {
  1414. readingsBulkUpdate( $hash, $reading,
  1415. $return->{e2service}{$e2reading} );
  1416. # channel
  1417. if ( $reading eq "servicename" ) {
  1418. my $val = $return->{e2service}{$e2reading};
  1419. $val =~ s/\s/_/g;
  1420. readingsBulkUpdate( $hash, "channel", $val );
  1421. }
  1422. # currentMedia
  1423. readingsBulkUpdate( $hash, "currentMedia",
  1424. $return->{e2service}{$e2reading} )
  1425. if $reading eq "servicereference";
  1426. }
  1427. # input
  1428. if ( $reading eq "servicereference" ) {
  1429. my @servicetype =
  1430. split( /:/, $return->{e2service}{$e2reading} );
  1431. if ( defined( $servicetype[2] )
  1432. && $servicetype[2] ne "2"
  1433. && $servicetype[2] ne "10" )
  1434. {
  1435. Log3 $name, 5,
  1436. "ENIGMA2 $name: detected servicereference type: tv";
  1437. readingsBulkUpdate( $hash, "input", "tv" )
  1438. if (
  1439. ReadingsVal( $name, "input", "" ) ne "tv" );
  1440. }
  1441. elsif (
  1442. defined( $servicetype[2] )
  1443. && ( $servicetype[2] eq "2"
  1444. || $servicetype[2] eq "10" )
  1445. )
  1446. {
  1447. Log3 $name, 5,
  1448. "ENIGMA2 $name: detected servicereference type: radio";
  1449. readingsBulkUpdateIfChanged( $hash, "input",
  1450. "radio" );
  1451. }
  1452. else {
  1453. Log3 $name, 2,
  1454. "ENIGMA2 $name: ERROR: servicereference type could not be detected (neither 'tv' nor 'radio')";
  1455. }
  1456. }
  1457. }
  1458. else {
  1459. Log3 $name, 5,
  1460. "ENIGMA2 $name: received no value for reading $reading";
  1461. if ( ReadingsVal( $name, $reading, "" ) ne "-" ) {
  1462. readingsBulkUpdate( $hash, $reading, "-" );
  1463. # channel
  1464. readingsBulkUpdate( $hash, "channel", "-" )
  1465. if $reading eq "servicename";
  1466. # currentMedia
  1467. readingsBulkUpdate( $hash, "currentMedia", "-" )
  1468. if $reading eq "servicereference";
  1469. }
  1470. }
  1471. }
  1472. # Event readings
  1473. #
  1474. if ( defined( $return->{e2eventlist} ) ) {
  1475. my $eventNow;
  1476. my $eventNext;
  1477. if ( ref( $return->{e2eventlist}{e2event} ) eq "ARRAY" ) {
  1478. Log3 $name, 5,
  1479. "ENIGMA2 $name: detected multiple event details";
  1480. $eventNow = $return->{e2eventlist}{e2event}[0];
  1481. $eventNext = $return->{e2eventlist}{e2event}[1]
  1482. if ( defined( $return->{e2eventlist}{e2event}[1] ) );
  1483. }
  1484. else {
  1485. Log3 $name, 5,
  1486. "ENIGMA2 $name: detected single event details";
  1487. $eventNow = $return->{e2eventlist}{e2event};
  1488. }
  1489. foreach my $reading (
  1490. "eventstart", "eventduration",
  1491. "eventremaining", "eventcurrenttime",
  1492. "eventdescription", "eventdescriptionextended",
  1493. "eventtitle", "eventname",
  1494. )
  1495. {
  1496. $e2reading = "e2" . $reading;
  1497. # current event
  1498. if ( defined( $eventNow->{$e2reading} )
  1499. && lc( $eventNow->{$e2reading} ) ne "n/a"
  1500. && $eventNow->{$e2reading} ne "0"
  1501. && $eventNow->{$e2reading} ne "" )
  1502. {
  1503. Log3 $name, 5,
  1504. "ENIGMA2 $name: detected valid reading $e2reading for current event";
  1505. if ( ReadingsVal( $name, $reading, "" ) ne
  1506. $eventNow->{$e2reading} )
  1507. {
  1508. readingsBulkUpdate( $hash, $reading,
  1509. $eventNow->{$e2reading} );
  1510. # currentTitle
  1511. readingsBulkUpdate( $hash, "currentTitle",
  1512. $eventNow->{$e2reading} )
  1513. if $reading eq "eventtitle";
  1514. }
  1515. }
  1516. else {
  1517. Log3 $name, 5,
  1518. "ENIGMA2 $name: no valid reading $e2reading found for current event";
  1519. if ( ReadingsVal( $name, $reading, "" ) ne "-" ) {
  1520. readingsBulkUpdate( $hash, $reading, "-" );
  1521. # currentTitle
  1522. readingsBulkUpdate( $hash, "currentTitle", "-" )
  1523. if $reading eq "eventtitle";
  1524. }
  1525. }
  1526. # next event
  1527. my $readingN = $reading . "_next";
  1528. if ( defined( $eventNext->{$e2reading} )
  1529. && lc( $eventNext->{$e2reading} ) ne "n/a"
  1530. && $eventNext->{$e2reading} ne "0"
  1531. && $eventNext->{$e2reading} ne "" )
  1532. {
  1533. Log3 $name, 5,
  1534. "ENIGMA2 $name: detected valid reading $e2reading for next event";
  1535. if ( ReadingsVal( $name, $readingN, "" ) ne
  1536. $eventNext->{$e2reading} )
  1537. {
  1538. readingsBulkUpdate( $hash, $readingN,
  1539. $eventNext->{$e2reading} );
  1540. # nextTitle
  1541. readingsBulkUpdate( $hash, "nextTitle",
  1542. $eventNext->{$e2reading} )
  1543. if $readingN eq "eventtitle_next";
  1544. }
  1545. }
  1546. else {
  1547. Log3 $name, 5,
  1548. "ENIGMA2 $name: no valid reading $e2reading found for next event";
  1549. if ( ReadingsVal( $name, $readingN, "" ) ne "-" ) {
  1550. readingsBulkUpdate( $hash, $readingN, "-" );
  1551. # nextTitle
  1552. readingsBulkUpdate( $hash, "nextTitle", "-" )
  1553. if $readingN eq "eventtitle_next";
  1554. }
  1555. }
  1556. }
  1557. # convert date+time into human readable formats
  1558. foreach my $readingO (
  1559. "eventstart", "eventcurrenttime",
  1560. "eventduration", "eventremaining"
  1561. )
  1562. {
  1563. $reading = $readingO . "_hr";
  1564. $e2reading = "e2" . $readingO;
  1565. # current event
  1566. if ( defined( $eventNow->{$e2reading} )
  1567. && $eventNow->{$e2reading} ne "0"
  1568. && $eventNow->{$e2reading} ne "" )
  1569. {
  1570. my $timestring;
  1571. if ( $readingO eq "eventduration"
  1572. || $readingO eq "eventremaining" )
  1573. {
  1574. my @t = localtime( $eventNow->{$e2reading} );
  1575. $timestring = sprintf( "%02d:%02d:%02d",
  1576. $t[2] - 1,
  1577. $t[1], $t[0] );
  1578. }
  1579. else {
  1580. $timestring =
  1581. substr(
  1582. FmtDateTime( $eventNow->{$e2reading} ),
  1583. 11 );
  1584. }
  1585. readingsBulkUpdateIfChanged( $hash, $reading,
  1586. $timestring );
  1587. }
  1588. else {
  1589. readingsBulkUpdateIfChanged( $hash, $reading, "-" );
  1590. }
  1591. # next event
  1592. $reading = $readingO . "_next_hr";
  1593. if ( defined( $eventNext->{$e2reading} )
  1594. && $eventNext->{$e2reading} ne "0"
  1595. && $eventNext->{$e2reading} ne "" )
  1596. {
  1597. my $timestring;
  1598. if ( $readingO eq "eventduration"
  1599. || $readingO eq "eventremaining" )
  1600. {
  1601. my @t = localtime( $eventNext->{$e2reading} );
  1602. $timestring = sprintf( "%02d:%02d:%02d",
  1603. $t[2] - 1,
  1604. $t[1], $t[0] );
  1605. }
  1606. else {
  1607. $timestring =
  1608. substr(
  1609. FmtDateTime( $eventNext->{$e2reading} ),
  1610. 11 );
  1611. }
  1612. readingsBulkUpdateIfChanged( $hash, $reading,
  1613. $timestring );
  1614. }
  1615. else {
  1616. readingsBulkUpdateIfChanged( $hash, $reading, "-" );
  1617. }
  1618. }
  1619. }
  1620. }
  1621. else {
  1622. Log3 $name, 2,
  1623. "ENIGMA2 $name: ERROR: current service info could not be read - /getcurrent sent malformed response";
  1624. }
  1625. }
  1626. # timerlist
  1627. elsif ( $service eq "timerlist" ) {
  1628. my $activeRecordings = 0;
  1629. my %recordings;
  1630. my $recordingsNext_time = "0";
  1631. my $recordingsNext_time_hr = "-";
  1632. my $recordingsNext_counter = "0";
  1633. my $recordingsNext_counter_hr = "-";
  1634. my $recordingsNextServicename = "-";
  1635. my $recordingsNextName = "-";
  1636. my $recordingsError = 0;
  1637. my $recordingsFinished = 0;
  1638. if ( ref($return) eq "HASH" ) {
  1639. if ( ref( $return->{e2timer} ) eq "HASH" ) {
  1640. Log3 $name, 5,
  1641. "ENIGMA2 $name: detected single event in timerlist";
  1642. # queued recording
  1643. if (
  1644. defined( $return->{e2timer}{e2state} )
  1645. && $return->{e2timer}{e2state} eq "0"
  1646. && ( !defined( $return->{e2timer}{e2disabled} )
  1647. || $return->{e2timer}{e2disabled} eq "0" )
  1648. && defined( $return->{e2timer}{e2eit} )
  1649. && defined( $return->{e2timer}{e2servicename} )
  1650. && defined( $return->{e2timer}{e2name} )
  1651. )
  1652. {
  1653. my $timeleft =
  1654. $return->{e2timer}{e2startprepare} - time();
  1655. # only add if starttime is smaller
  1656. if ( $recordingsNext_time eq "0"
  1657. || $timeleft < $recordingsNext_time - time() )
  1658. {
  1659. my @t =
  1660. localtime( $return->{e2timer}{e2startprepare} );
  1661. $recordingsNext_time =
  1662. $return->{e2timer}{e2startprepare};
  1663. $recordingsNext_time_hr =
  1664. sprintf( "%02d:%02d:%02d", $t[2], $t[1], $t[0] );
  1665. $recordingsNext_counter = int( $timeleft + 0.5 );
  1666. $recordingsNextServicename =
  1667. $return->{e2timer}{e2servicename};
  1668. $recordingsNextName = $return->{e2timer}{e2name};
  1669. # human readable
  1670. my @t2 = localtime($timeleft);
  1671. $recordingsNext_counter_hr =
  1672. sprintf( "%02d:%02d:%02d",
  1673. $t2[2] - 1,
  1674. $t2[1], $t2[0] );
  1675. }
  1676. }
  1677. # failed recording
  1678. if ( defined( $return->{e2timer}{e2state} )
  1679. && $return->{e2timer}{e2state} eq "1" )
  1680. {
  1681. $recordingsError++;
  1682. }
  1683. # active recording
  1684. if ( defined( $return->{e2timer}{e2state} )
  1685. && $return->{e2timer}{e2state} eq "2"
  1686. && defined( $return->{e2timer}{e2servicename} )
  1687. && defined( $return->{e2timer}{e2name} ) )
  1688. {
  1689. $activeRecordings++;
  1690. $recordings{$activeRecordings}{servicename} =
  1691. $return->{e2timer}{e2servicename};
  1692. $recordings{$activeRecordings}{name} =
  1693. $return->{e2timer}{e2name};
  1694. }
  1695. # finished recording
  1696. if ( defined( $return->{e2timer}{e2state} )
  1697. && $return->{e2timer}{e2state} eq "3" )
  1698. {
  1699. $recordingsFinished++;
  1700. }
  1701. }
  1702. elsif ( ref( $return->{e2timer} ) eq "ARRAY" ) {
  1703. Log3 $name, 5,
  1704. "ENIGMA2 $name: detected multiple events in timerlist";
  1705. my $i = 0;
  1706. my $arr_size = @{ $return->{e2timer} };
  1707. while ( $i < $arr_size ) {
  1708. # queued recording
  1709. if (
  1710. defined( $return->{e2timer}[$i]{e2state} )
  1711. && $return->{e2timer}[$i]{e2state} eq "0"
  1712. && ( !defined( $return->{e2timer}[$i]{e2disabled} )
  1713. || $return->{e2timer}[$i]{e2disabled} eq "0" )
  1714. && defined( $return->{e2timer}[$i]{e2eit} )
  1715. && defined( $return->{e2timer}[$i]{e2servicename} )
  1716. && defined( $return->{e2timer}[$i]{e2name} )
  1717. )
  1718. {
  1719. my $timeleft =
  1720. $return->{e2timer}[$i]{e2startprepare} - time();
  1721. # only add if starttime is smaller
  1722. if ( $recordingsNext_time eq "0"
  1723. || $timeleft < $recordingsNext_time - time() )
  1724. {
  1725. my @t =
  1726. localtime(
  1727. $return->{e2timer}[$i]{e2startprepare} );
  1728. $recordingsNext_time =
  1729. $return->{e2timer}[$i]{e2startprepare};
  1730. $recordingsNext_time_hr =
  1731. sprintf( "%02d:%02d:%02d",
  1732. $t[2], $t[1], $t[0] );
  1733. $recordingsNext_counter = $timeleft;
  1734. $recordingsNextServicename =
  1735. $return->{e2timer}[$i]{e2servicename};
  1736. $recordingsNextName =
  1737. $return->{e2timer}[$i]{e2name};
  1738. # human readable
  1739. my @t2 = localtime($timeleft);
  1740. $recordingsNext_counter_hr =
  1741. sprintf( "%02d:%02d:%02d",
  1742. $t2[2] - 1,
  1743. $t2[1], $t2[0] );
  1744. }
  1745. }
  1746. # failed recording
  1747. if ( defined( $return->{e2timer}[$i]{e2state} )
  1748. && $return->{e2timer}[$i]{e2state} eq "1" )
  1749. {
  1750. $recordingsError++;
  1751. }
  1752. # active recording
  1753. if ( defined( $return->{e2timer}[$i]{e2state} )
  1754. && $return->{e2timer}[$i]{e2state} eq "2"
  1755. && defined( $return->{e2timer}[$i]{e2servicename} )
  1756. && defined( $return->{e2timer}[$i]{e2name} ) )
  1757. {
  1758. $activeRecordings++;
  1759. $recordings{$activeRecordings}{servicename} =
  1760. $return->{e2timer}[$i]{e2servicename};
  1761. $recordings{$activeRecordings}{name} =
  1762. $return->{e2timer}[$i]{e2name};
  1763. }
  1764. # finished recording
  1765. if ( defined( $return->{e2timer}[$i]{e2state} )
  1766. && $return->{e2timer}[$i]{e2state} eq "3" )
  1767. {
  1768. $recordingsFinished++;
  1769. }
  1770. $i++;
  1771. }
  1772. }
  1773. }
  1774. else {
  1775. Log3 $name, 5, "ENIGMA2 $name: timerlist seems to be empty";
  1776. }
  1777. my $recordingsElementsCount = scalar( keys %recordings );
  1778. my $readingname;
  1779. readingsBulkUpdateIfChanged( $hash, "recordings",
  1780. $recordingsElementsCount );
  1781. my $ri = 0;
  1782. if ( $recordingsElementsCount > 0 ) {
  1783. while ( $ri < $recordingsElementsCount ) {
  1784. $ri++;
  1785. $readingname = "recordings" . $ri . "_servicename";
  1786. readingsBulkUpdateIfChanged( $hash, $readingname, $2 )
  1787. if ( $recordings{$ri}{servicename} =~
  1788. /^(\s*[\[\(\{].*[\]\)\}]\s*)?([\s\w\(\)_-]+)(\s*[\[\(\{].*[\]\)\}]\s*)?$/
  1789. );
  1790. $readingname = "recordings" . $ri . "_name";
  1791. readingsBulkUpdateIfChanged( $hash, $readingname, $2 )
  1792. if ( $recordings{$ri}{name} =~
  1793. /^(\s*[\[\(\{].*[\]\)\}]\s*)?([\s\w\(\)_-]+)(\s*[\[\(\{].*[\]\)\}]\s*)?$/
  1794. );
  1795. }
  1796. }
  1797. # clear inactive recordingsX_* readings
  1798. foreach my $recReading (
  1799. grep { /^recordings\d+_.*/ }
  1800. keys %{ $defs{$name}{READINGS} }
  1801. )
  1802. {
  1803. next if ( $recReading =~ m/^recordings(\d+).*/ && $1 <= $ri );
  1804. Log3 $name, 5,
  1805. "ENIGMA2 $name: old reading $recReading was deleted";
  1806. # trigger event before deleting this reading to notify GUI
  1807. readingsBulkUpdateIfChanged( $hash, $recReading, "" );
  1808. delete( $defs{$name}{READINGS}{$recReading} );
  1809. }
  1810. readingsBulkUpdateIfChanged( $hash, "recordings_next",
  1811. $recordingsNext_time );
  1812. readingsBulkUpdateIfChanged( $hash, "recordings_next_hr",
  1813. $recordingsNext_time_hr );
  1814. readingsBulkUpdateIfChanged( $hash, "recordings_next_counter",
  1815. $recordingsNext_counter );
  1816. readingsBulkUpdateIfChanged( $hash, "recordings_next_counter_hr",
  1817. $recordingsNext_counter_hr );
  1818. readingsBulkUpdateIfChanged( $hash, "recordings_next_servicename",
  1819. $recordingsNextServicename );
  1820. readingsBulkUpdateIfChanged( $hash, "recordings_next_name",
  1821. $recordingsNextName );
  1822. readingsBulkUpdateIfChanged( $hash, "recordings_error",
  1823. $recordingsError );
  1824. readingsBulkUpdateIfChanged( $hash, "recordings_finished",
  1825. $recordingsFinished );
  1826. }
  1827. # volume
  1828. elsif ( $service eq "vol" ) {
  1829. if ( ref($return) eq "HASH" && defined( $return->{e2current} ) ) {
  1830. readingsBulkUpdateIfChanged( $hash, "volume",
  1831. $return->{e2current} );
  1832. }
  1833. else {
  1834. Log3 $name, 5,
  1835. "ENIGMA2 $name: ERROR: no volume could be extracted";
  1836. }
  1837. if ( ref($return) eq "HASH" && defined( $return->{e2ismuted} ) ) {
  1838. my $muteState = "on";
  1839. $muteState = "off"
  1840. if ( lc( $return->{e2ismuted} ) eq "false" );
  1841. readingsBulkUpdateIfChanged( $hash, "mute", $muteState );
  1842. }
  1843. else {
  1844. Log3 $name, 5,
  1845. "ENIGMA2 $name: ERROR: no mute state could be extracted";
  1846. }
  1847. }
  1848. # signal
  1849. elsif ( $service eq "signal" ) {
  1850. my $reading;
  1851. my $e2reading;
  1852. if ( ref($return) eq "HASH"
  1853. && defined( $return->{e2snrdb} ) )
  1854. {
  1855. foreach my $reading ( "snrdb", "snr", "ber", "acg", ) {
  1856. $e2reading = "e2" . $reading;
  1857. if ( defined( $return->{$e2reading} )
  1858. && lc( $return->{$e2reading} ) ne "n/a" )
  1859. {
  1860. my @value = split( / /, $return->{$e2reading} );
  1861. if ( defined( $value[1] ) || $reading eq "ber" ) {
  1862. readingsBulkUpdate( $hash, $reading, $value[0] );
  1863. }
  1864. else {
  1865. readingsBulkUpdate( $hash, $reading, "0" );
  1866. }
  1867. }
  1868. else {
  1869. readingsBulkUpdate( $hash, $reading, "0" );
  1870. }
  1871. }
  1872. }
  1873. else {
  1874. Log3 $name, 5,
  1875. "ENIGMA2 $name: ERROR: no signal information could be found";
  1876. }
  1877. }
  1878. # all other command results
  1879. else {
  1880. ENIGMA2_GetStatus( $hash, 1 );
  1881. }
  1882. }
  1883. # Set reading for power
  1884. #
  1885. my $readingPower = "off";
  1886. $readingPower = "on"
  1887. if ( $state eq "on" );
  1888. readingsBulkUpdateIfChanged( $hash, "power", $readingPower );
  1889. # Set reading for state
  1890. #
  1891. readingsBulkUpdateIfChanged( $hash, "state", $state );
  1892. # Set reading for stateAV
  1893. my $stateAV = ENIGMA2_GetStateAV($hash);
  1894. readingsBulkUpdateIfChanged( $hash, "stateAV", $stateAV );
  1895. # Set ENIGMA2 online-only readings to "-" in case box is in
  1896. # offline or in standby mode
  1897. if ( $state eq "off"
  1898. || $state eq "absent"
  1899. || $state eq "undefined" )
  1900. {
  1901. foreach my $reading (
  1902. 'servicename', 'providername',
  1903. 'servicereference', 'videowidth',
  1904. 'videoheight', 'servicevideosize',
  1905. 'apid', 'vpid',
  1906. 'pcrpid', 'pmtpid',
  1907. 'txtpid', 'tsid',
  1908. 'onid', 'sid',
  1909. 'iswidescreen', 'mute',
  1910. 'channel', 'currentTitle',
  1911. 'nextTitle', 'currentMedia',
  1912. 'eventcurrenttime', 'eventcurrenttime_hr',
  1913. 'eventdescription', 'eventdescriptionextended',
  1914. 'eventduration', 'eventduration_hr',
  1915. 'eventremaining', 'eventremaining_hr',
  1916. 'eventstart', 'eventstart_hr',
  1917. 'eventtitle', 'eventname',
  1918. 'eventcurrenttime_next', 'eventcurrenttime_next_hr',
  1919. 'eventdescription_next', 'eventdescriptionextended_next',
  1920. 'eventduration_next', 'eventduration_next_hr',
  1921. 'eventremaining_next', 'eventremaining_next_hr',
  1922. 'eventstart_next', 'eventstart_next_hr',
  1923. 'eventtitle_next', 'eventname_next',
  1924. )
  1925. {
  1926. readingsBulkUpdateIfChanged( $hash, $reading, "-" );
  1927. }
  1928. # special handling for signal values
  1929. foreach my $reading ( 'acg', 'ber', 'snr', 'snrdb', ) {
  1930. readingsBulkUpdateIfChanged( $hash, $reading, "0" );
  1931. }
  1932. }
  1933. # Set ENIGMA2 online+standby readings to "-" in case box is in
  1934. # offline mode
  1935. if ( $state eq "absent" || $state eq "undefined" ) {
  1936. readingsBulkUpdateIfChanged( $hash, "input", "-" );
  1937. }
  1938. readingsEndUpdate( $hash, 1 );
  1939. undef $return;
  1940. return;
  1941. }
  1942. ###################################
  1943. sub ENIGMA2_Undefine($$) {
  1944. my ( $hash, $arg ) = @_;
  1945. my $name = $hash->{NAME};
  1946. Log3 $name, 5, "ENIGMA2 $name: called function ENIGMA2_Undefine()";
  1947. # Stop the internal GetStatus-Loop and exit
  1948. RemoveInternalTimer($hash);
  1949. return;
  1950. }
  1951. ###################################
  1952. sub ENIGMA2_GetStateAV($) {
  1953. my ($hash) = @_;
  1954. my $name = $hash->{NAME};
  1955. if ( ReadingsVal( $name, "presence", "absent" ) eq "absent" ) {
  1956. return "absent";
  1957. }
  1958. elsif ( ReadingsVal( $name, "power", "off" ) eq "off" ) {
  1959. return "off";
  1960. }
  1961. elsif ( ReadingsVal( $name, "mute", "off" ) eq "on" ) {
  1962. return "muted";
  1963. }
  1964. elsif ( ReadingsVal( $name, "playStatus", "stopped" ) ne "stopped" ) {
  1965. return ReadingsVal( $name, "playStatus", "stopped" );
  1966. }
  1967. else {
  1968. return ReadingsVal( $name, "power", "off" );
  1969. }
  1970. }
  1971. ###################################
  1972. sub ENIGMA2_wake ($$) {
  1973. if ( !$modules{WOL}{LOADED} && -f "$attr{global}{modpath}/FHEM/98_WOL.pm" )
  1974. {
  1975. my $ret = CommandReload( undef, "98_WOL" );
  1976. return $ret if ($ret);
  1977. }
  1978. elsif ( !-f "$attr{global}{modpath}/FHEM/98_WOL.pm" ) {
  1979. return "Missing module: $attr{global}{modpath}/FHEM/98_WOL.pm";
  1980. }
  1981. my ( $name, $mac ) = @_;
  1982. my $hash = $defs{$name};
  1983. my $host =
  1984. AttrVal( $name, "WOL_useUdpBroadcast",
  1985. AttrVal( $name, "useUdpBroadcast", "255.255.255.255" ) );
  1986. my $port = AttrVal( $name, "WOL_port", "9" );
  1987. my $mode = lc( AttrVal( $name, "WOL_mode", "UDP" ) );
  1988. Log3 $name, 4,
  1989. "ENIGMA2 $name: Waking up by sending Wake-On-Lan magic package to "
  1990. . $mac;
  1991. if ( $mode eq "both" || $mode eq "ew" ) {
  1992. WOL_by_ew( $hash, $mac );
  1993. }
  1994. if ( $mode eq "both" || $mode eq "udp" ) {
  1995. WOL_by_udp( $hash, $mac, $host, $port );
  1996. }
  1997. }
  1998. #####################################
  1999. # Callback from 95_remotecontrol for command makenotify.
  2000. sub ENIGMA2_RCmakenotify($$) {
  2001. my ( $nam, $ndev ) = @_;
  2002. my $nname = "notify_$nam";
  2003. fhem( "define $nname notify $nam set $ndev remoteControl " . '$EVENT', 1 );
  2004. Log3 undef, 2, "[remotecontrol:ENIGMA2] Notify created: $nname";
  2005. return "Notify created by ENIGMA2: $nname";
  2006. }
  2007. #####################################
  2008. # RC layouts
  2009. # Dreambox DM500 + DM800 with SVG
  2010. sub ENIGMA2_RClayout_DM800_SVG() {
  2011. my @row;
  2012. $row[0] = ":rc_BLANK.svg,:rc_BLANK.svg,POWER:rc_POWER.svg";
  2013. $row[1] = ":rc_BLANK.svg,:rc_BLANK.svg,:rc_BLANK.svg";
  2014. $row[2] = "1:rc_1.svg,2:rc_2.svg,3:rc_3.svg";
  2015. $row[3] = "4:rc_4.svg,5:rc_5.svg,6:rc_6.svg";
  2016. $row[4] = "7:rc_7.svg,8:rc_8.svg,9:rc_9.svg";
  2017. $row[5] = "LEFTBRACE:rc_PREVIOUS.svg,0:rc_0.svg,RIGHTBRACE:rc_NEXT.svg";
  2018. $row[6] = ":rc_BLANK.svg,:rc_BLANK.svg,:rc_BLANK.svg";
  2019. $row[7] = "VOLUMEUP:rc_VOLPLUS.svg,MUTE:rc_MUTE.svg,CHANNELUP:rc_UP.svg";
  2020. $row[8] =
  2021. "VOLUMEDOWN:rc_VOLMINUS.svg,EXIT:rc_EXIT.svg,CHANNELDOWN:rc_DOWN.svg";
  2022. $row[9] = ":rc_BLANK.svg,:rc_BLANK.svg,:rc_BLANK.svg";
  2023. $row[10] = "INFO:rc_INFO.svg,UP:rc_UP.svg,MENU:rc_MENU.svg";
  2024. $row[11] = "LEFT:rc_LEFT.svg,OK:rc_OK.svg,RIGHT:rc_RIGHT.svg";
  2025. $row[12] = "AUDIO:rc_AUDIO.svg,DOWN:rc_DOWN.svg,VIDEO:rc_VIDEO.svg";
  2026. $row[13] = ":rc_BLANK.svg,EXIT:rc_EXIT.svg,:rc_BLANK.svg";
  2027. $row[14] =
  2028. "RED:rc_REWred.svg,GREEN:rc_PLAYgreen.svg,YELLOW:rc_PAUSEyellow.svg,BLUE:rc_FFblue.svg";
  2029. $row[15] =
  2030. "TV:rc_TVstop.svg,RADIO:rc_RADIOred.svg,TEXT:rc_TEXT.svg,HELP:rc_HELP.svg";
  2031. $row[16] = "attr rc_iconpath icons/remotecontrol";
  2032. $row[17] = "attr rc_iconprefix black_btn_";
  2033. return @row;
  2034. }
  2035. # Dreambox DM500 + DM800 with PNG
  2036. sub ENIGMA2_RClayout_DM800() {
  2037. my @row;
  2038. $row[0] = ":blank,:blank,POWER:POWEROFF";
  2039. $row[1] = ":blank,:blank,:blank";
  2040. $row[2] = "1,2,3";
  2041. $row[3] = "4,5,6";
  2042. $row[4] = "7,8,9";
  2043. $row[5] = "LEFTBRACE:LEFT2,0:0,RIGHTBRACE:RIGHT2";
  2044. $row[6] = ":blank,:blank,:blank";
  2045. $row[7] = "VOLUMEUP:VOLUP,MUTE,CHANNELUP:CHUP2";
  2046. $row[8] = "VOLUMEDOWN:VOLDOWN,EXIT,CHANNELDOWN:CHDOWN2";
  2047. $row[9] = ":blank,:blank,:blank";
  2048. $row[10] = "INFO,UP,MENU";
  2049. $row[11] = "LEFT,OK,RIGHT";
  2050. $row[12] = "AUDIO,DOWN,VIDEO";
  2051. $row[13] = ":blank,:blank,:blank";
  2052. $row[14] = "RED:REWINDred,GREEN:PLAYgreen,YELLOW:PAUSEyellow,BLUE:FFblue";
  2053. $row[15] = "TV:TVstop,RADIO:RADIOred,TEXT,HELP";
  2054. $row[16] = "attr rc_iconpath icons/remotecontrol";
  2055. $row[17] = "attr rc_iconprefix black_btn_";
  2056. return @row;
  2057. }
  2058. # Dreambox DM800se + DM8000 with SVG
  2059. sub ENIGMA2_RClayout_DM8000_SVG() {
  2060. my @row;
  2061. $row[0] = ":rc_BLANK.svg,:rc_BLANK.svg,POWER:rc_POWER.svg";
  2062. $row[1] = ":rc_BLANK.svg,:rc_BLANK.svg,:rc_BLANK.svg";
  2063. $row[2] = "1:rc_1.svg,2:rc_2.svg,3:rc_3.svg";
  2064. $row[3] = "4:rc_4.svg,5:rc_5.svg,6:rc_6.svg";
  2065. $row[4] = "7:rc_7.svg,8:rc_8.svg,9:rc_9.svg";
  2066. $row[5] = "LEFTBRACE:rc_PREVIOUS.svg,0:rc_0.svg,RIGHTBRACE:rc_NEXT.svg";
  2067. $row[6] = ":rc_BLANK.svg,:rc_BLANK.svg,:rc_BLANK.svg";
  2068. $row[7] = "VOLUMEUP:rc_VOLPLUS.svg,MUTE:rc_MUTE.svg,CHANNELUP:rc_UP.svg";
  2069. $row[8] =
  2070. "VOLUMEDOWN:rc_VOLMINUS.svg,EXIT:rc_EXIT.svg,CHANNELDOWN:rc_DOWN.svg";
  2071. $row[9] = ":rc_BLANK.svg,:rc_BLANK.svg,:rc_BLANK.svg";
  2072. $row[10] = "INFO:rc_INFO.svg,UP:rc_UP.svg,MENU:rc_MENU.svg";
  2073. $row[11] = "LEFT:rc_LEFT.svg,OK:rc_OK.svg,RIGHT:rc_RIGHT.svg";
  2074. $row[12] = "AUDIO:rc_AUDIO.svg,DOWN:rc_DOWN.svg,VIDEO:rc_VIDEO.svg";
  2075. $row[13] = ":rc_BLANK.svg,EXIT:rc_EXIT.svg,:rc_BLANK.svg";
  2076. $row[14] =
  2077. "RED:rc_RED.svg,GREEN:rc_GREEN.svg,YELLOW:rc_YELLOW.svg,BLUE:rc_BLUE.svg";
  2078. $row[15] =
  2079. "REWIND:rc_REW.svg,PLAY:rc_PLAY.svg,STOP:rc_STOP.svg,FASTFORWARD:rc_FF.svg";
  2080. $row[16] =
  2081. "TV:rc_TV.svg,RADIO:rc_RADIO.svg,TEXT:rc_TEXT.svg,RECORD:rc_REC.svg";
  2082. $row[17] = "attr rc_iconpath icons/remotecontrol";
  2083. $row[18] = "attr rc_iconprefix black_btn_";
  2084. return @row;
  2085. }
  2086. # Dreambox DM800se + DM8000 with PNG
  2087. sub ENIGMA2_RClayout_DM8000() {
  2088. my @row;
  2089. $row[0] = ":blank,:blank,POWER:POWEROFF";
  2090. $row[1] = ":blank,:blank,:blank";
  2091. $row[2] = "1,2,3";
  2092. $row[3] = "4,5,6";
  2093. $row[4] = "7,8,9";
  2094. $row[5] = "LEFTBRACE:LEFT2,0:0,RIGHTBRACE:RIGHT2";
  2095. $row[6] = ":blank,:blank,:blank";
  2096. $row[7] = "VOLUMEUP:VOLUP,MUTE,CHANNELUP:CHUP2";
  2097. $row[8] = "VOLUMEDOWN:VOLDOWN,EXIT,CHANNELDOWN:CHDOWN2";
  2098. $row[9] = ":blank,:blank,:blank";
  2099. $row[10] = "INFO,UP,MENU";
  2100. $row[11] = "LEFT,OK,RIGHT";
  2101. $row[12] = "AUDIO,DOWN,VIDEO";
  2102. $row[13] = ":blank,:blank,:blank";
  2103. $row[14] = "RED,GREEN,YELLOW,BLUE";
  2104. $row[15] = "REWIND,PLAY,STOP,FASTFORWARD:FF";
  2105. $row[16] = "TV,RADIO,TEXT,RECORD:REC";
  2106. $row[17] = "attr rc_iconpath icons/remotecontrol";
  2107. $row[18] = "attr rc_iconprefix black_btn_";
  2108. return @row;
  2109. }
  2110. # Dreambox RC10 with SVG
  2111. sub ENIGMA2_RClayout_RC10_SVG() {
  2112. my @row;
  2113. $row[0] = ":rc_BLANK.svg,:rc_BLANK.svg,POWER:rc_POWER.svg";
  2114. $row[1] = ":rc_BLANK.svg,:rc_BLANK.svg,:rc_BLANK.svg";
  2115. $row[2] = "1:rc_1.svg,2:rc_2.svg,3:rc_3.svg";
  2116. $row[3] = "4:rc_4.svg,5:rc_5.svg,6:rc_6.svg";
  2117. $row[4] = "7:rc_7.svg,8:rc_8.svg,9:rc_9.svg";
  2118. $row[5] = "LEFTBRACE:rc_PREVIOUS.svg,0:rc_0.svg,RIGHTBRACE:rc_NEXT.svg";
  2119. $row[6] =
  2120. "RED:rc_RED.svg,GREEN:rc_GREEN.svg,YELLOW:rc_YELLOW.svg,BLUE:rc_BLUE.svg";
  2121. $row[7] = ":rc_BLANK.svg,:rc_BLANK.svg,:rc_BLANK.svg";
  2122. $row[8] = "INFO:rc_INFO.svg,UP:rc_UP.svg,MENU:rc_MENU.svg";
  2123. $row[9] = "LEFT:rc_LEFT.svg,OK:rc_OK.svg,RIGHT:rc_RIGHT.svg";
  2124. $row[10] = "AUDIO:rc_AUDIO.svg,DOWN:rc_DOWN.svg,VIDEO:rc_VIDEO.svg";
  2125. $row[11] = ":rc_BLANK.svg,EXIT:rc_EXIT.svg,:rc_BLANK.svg";
  2126. $row[12] = "VOLUMEUP:rc_VOLPLUS.svg,:rc_BLANK.svg,CHANNELUP:rc_UP.svg";
  2127. $row[13] =
  2128. "VOLUMEDOWN:rc_VOLMINUS.svg,MUTE:rc_MUTE.svg,CHANNELDOWN:rc_DOWN.svg";
  2129. $row[14] = ":rc_BLANK.svg,:rc_BLANK.svg,:rc_BLANK.svg";
  2130. $row[15] =
  2131. "REWIND:rc_REW.svg,PLAY:rc_PLAY.svg,STOP:rc_STOP.svg,FASTFORWARD:rc_FF.svg";
  2132. $row[16] =
  2133. "TV:rc_TV.svg,RADIO:rc_RADIO.svg,TEXT:rc_TEXT.svg,RECORD:rc_REC.svg";
  2134. $row[17] = "attr rc_iconpath icons";
  2135. $row[18] = "attr rc_iconprefix rc_";
  2136. return @row;
  2137. }
  2138. # Dreambox RC10 with PNG
  2139. sub ENIGMA2_RClayout_RC10() {
  2140. my @row;
  2141. $row[0] = ":blank,:blank,POWER:POWEROFF";
  2142. $row[1] = ":blank,:blank,:blank";
  2143. $row[2] = "1,2,3";
  2144. $row[3] = "4,5,6";
  2145. $row[4] = "7,8,9";
  2146. $row[5] = "LEFTBRACE:LEFT2,0:0,RIGHTBRACE:RIGHT2";
  2147. $row[6] = "RED,GREEN,YELLOW,BLUE";
  2148. $row[7] = ":blank,:blank,:blank";
  2149. $row[8] = "INFO,UP,MENU";
  2150. $row[9] = "LEFT,OK,RIGHT";
  2151. $row[10] = "AUDIO,DOWN,VIDEO";
  2152. $row[11] = ":blank,EXIT,:blank";
  2153. $row[12] = "VOLUMEUP:VOLUP,:blank,CHANNELUP:CHUP2";
  2154. $row[13] = "VOLUMEDOWN:VOLDOWN,MUTE,CHANNELDOWN:CHDOWN2";
  2155. $row[14] = ":blank,:blank,:blank";
  2156. $row[15] = "REWIND,PLAY,STOP,FASTFORWARD:FF";
  2157. $row[16] = "TV,RADIO,TEXT,RECORD:REC";
  2158. $row[17] = "attr rc_iconpath icons/remotecontrol";
  2159. $row[18] = "attr rc_iconprefix black_btn_";
  2160. return @row;
  2161. }
  2162. # VU+ Duo2 with SVG
  2163. sub ENIGMA2_RClayout_VUplusDuo2_SVG() {
  2164. my @row;
  2165. $row[0] = ":rc_BLANK.svg,MUTE:rc_MUTE.svg,POWER:rc_POWER.svg";
  2166. $row[1] = ":rc_BLANK.svg,:rc_BLANK.svg,:rc_BLANK.svg";
  2167. $row[2] = "REWIND:rc_REW.svg,PLAY:rc_PLAY.svg,FASTFORWARD:rc_FF.svg";
  2168. $row[3] = "RECORD:rc_REC.svg,STOP:rc_STOP.svg,VIDEO:rc_VIDEO.svg";
  2169. $row[4] = ":rc_BLANK.svg,:rc_BLANK.svg,:rc_BLANK.svg";
  2170. $row[5] = "TV:rc_TV.svg,AUDIO:rc_AUDIO.svg,RADIO:rc_RADIO.svg";
  2171. $row[6] = "TEXT:rc_TEXT.svg,HELP:rc_HELP.svg,AV:rc_AV.svg";
  2172. $row[7] = "INFO:rc_EPG.svg,MENU:rc_MENU.svg,EXIT:rc_EXIT.svg";
  2173. $row[8] = ":rc_BLANK.svg,:rc_BLANK.svg,:rc_BLANK.svg";
  2174. $row[9] = "VOLUMEUP:rc_VOLPLUS.svg,UP:rc_UP.svg,CHANNELUP:rc_PLUS.svg";
  2175. $row[10] = "LEFT:rc_LEFT.svg,OK:rc_OK.svg,RIGHT:rc_RIGHT.svg";
  2176. $row[11] =
  2177. "VOLUMEDOWN:rc_VOLMINUS.svg,DOWN:rc_DOWN.svg,CHANNELDOWN:rc_MINUS.svg";
  2178. $row[12] = ":rc_BLANK.svg,:rc_BLANK.svg,:rc_BLANK.svg";
  2179. $row[13] =
  2180. "RED:rc_RED.svg,GREEN:rc_GREEN.svg,YELLOW:rc_YELLOW.svg,BLUE:rc_BLUE.svg";
  2181. $row[14] = "1:rc_1.svg,2:rc_2.svg,3:rc_3.svg";
  2182. $row[15] = "4:rc_4.svg,5:rc_5.svg,6:rc_6.svg";
  2183. $row[16] = "7:rc_7.svg,8:rc_8.svg,9:rc_9.svg";
  2184. $row[17] = "LEFTBRACE:rc_PREVIOUS.svg,0:rc_0.svg,RIGHTBRACE:rc_NEXT.svg";
  2185. $row[18] = "attr rc_iconpath icons";
  2186. $row[19] = "attr rc_iconprefix rc_";
  2187. return @row;
  2188. }
  2189. # VU+ Duo2 with PNG
  2190. sub ENIGMA2_RClayout_VUplusDuo2() {
  2191. my @row;
  2192. $row[0] = ":blank,MUTE,POWER:POWEROFF";
  2193. $row[1] = ":blank,:blank,:blank";
  2194. $row[2] = "REWIND,PLAY,FASTFORWARD:FF";
  2195. $row[3] = "RECORD:REC,STOP,VIDEO";
  2196. $row[4] = ":blank,:blank,:blank";
  2197. $row[5] = "TV,AUDIO,RADIO:RADIO";
  2198. $row[6] = "TEXT,HELP,AV";
  2199. $row[7] = "INFO,MENU,EXIT";
  2200. $row[8] = ":blank,:blank,:blank";
  2201. $row[9] = "VOLUMEUP:VOLUP,UP,CHANNELUP:CHUP2";
  2202. $row[10] = "LEFT,OK,RIGHT";
  2203. $row[11] = "VOLUMEDOWN:VOLDOWN,DOWN,CHANNELDOWN:CHDOWN2";
  2204. $row[12] = ":blank,:blank,:blank";
  2205. $row[13] = "RED,GREEN,YELLOW,BLUE";
  2206. $row[14] = "1,2,3";
  2207. $row[15] = "4,5,6";
  2208. $row[16] = "7,8,9";
  2209. $row[17] = "LEFTBRACE:LEFT2,0:0,RIGHTBRACE:RIGHT2";
  2210. $row[18] = "attr rc_iconpath icons/remotecontrol";
  2211. $row[19] = "attr rc_iconprefix black_btn_";
  2212. return @row;
  2213. }
  2214. ###################################
  2215. sub ENIGMA2_GetRemotecontrolCommand($) {
  2216. my ($command) = @_;
  2217. my $commands = {
  2218. 'RESERVED' => 0,
  2219. 'ESC' => 1,
  2220. '1' => 2,
  2221. '2' => 3,
  2222. '3' => 4,
  2223. '4' => 5,
  2224. '5' => 6,
  2225. '6' => 7,
  2226. '7' => 8,
  2227. '8' => 9,
  2228. '9' => 10,
  2229. '0' => 11,
  2230. 'MINUS' => 12,
  2231. 'EQUAL' => 13,
  2232. 'BACKSPACE' => 14,
  2233. 'TAB' => 15,
  2234. 'Q' => 16,
  2235. 'W' => 17,
  2236. 'E' => 18,
  2237. 'R' => 19,
  2238. 'T' => 20,
  2239. 'Y' => 21,
  2240. 'U' => 22,
  2241. 'I' => 23,
  2242. 'O' => 24,
  2243. 'P' => 25,
  2244. 'LEFTBRACE' => 26,
  2245. 'RIGHTBRACE' => 27,
  2246. 'ENTER' => 28,
  2247. 'LEFTCTRL' => 29,
  2248. 'A' => 30,
  2249. 'S' => 31,
  2250. 'D' => 32,
  2251. 'F' => 33,
  2252. 'G' => 34,
  2253. 'H' => 35,
  2254. 'J' => 36,
  2255. 'K' => 37,
  2256. 'L' => 38,
  2257. 'SEMICOLON' => 39,
  2258. 'APOSTROPHE' => 40,
  2259. 'GRAVE' => 41,
  2260. 'LEFTSHIFT' => 42,
  2261. 'BACKSLASH' => 43,
  2262. 'Z' => 44,
  2263. 'X' => 45,
  2264. 'C' => 46,
  2265. 'V' => 47,
  2266. 'B' => 48,
  2267. 'N' => 49,
  2268. 'M' => 50,
  2269. 'COMMA' => 51,
  2270. 'DOT' => 52,
  2271. 'SLASH' => 53,
  2272. 'RIGHTSHIFT' => 54,
  2273. 'KPASTERISK' => 55,
  2274. 'LEFTALT' => 56,
  2275. 'SPACE' => 57,
  2276. 'CAPSLOCK' => 58,
  2277. 'F1' => 59,
  2278. 'F2' => 60,
  2279. 'F3' => 61,
  2280. 'F4' => 62,
  2281. 'F5' => 63,
  2282. 'F6' => 64,
  2283. 'F7' => 65,
  2284. 'F8' => 66,
  2285. 'F9' => 67,
  2286. 'F10' => 68,
  2287. 'NUMLOCK' => 69,
  2288. 'SCROLLLOCK' => 70,
  2289. 'KP7' => 71,
  2290. 'KP8' => 72,
  2291. 'KP9' => 73,
  2292. 'KPMINUS' => 74,
  2293. 'KP4' => 75,
  2294. 'KP5' => 76,
  2295. 'KP6' => 77,
  2296. 'KPPLUS' => 78,
  2297. 'KP1' => 79,
  2298. 'KP2' => 80,
  2299. 'KP3' => 81,
  2300. 'KP0' => 82,
  2301. 'KPDOT' => 83,
  2302. '103RD' => 84,
  2303. 'F13' => 85,
  2304. '102ND' => 86,
  2305. 'F11' => 87,
  2306. 'F12' => 88,
  2307. 'F14' => 89,
  2308. 'F15' => 90,
  2309. 'F16' => 91,
  2310. 'F17' => 92,
  2311. 'F18' => 93,
  2312. 'F19' => 94,
  2313. 'F20' => 95,
  2314. 'KPENTER' => 96,
  2315. 'RIGHTCTRL' => 97,
  2316. 'KPSLASH' => 98,
  2317. 'SYSRQ' => 99,
  2318. 'RIGHTALT' => 100,
  2319. 'LINEFEED' => 101,
  2320. 'HOME' => 102,
  2321. 'UP' => 103,
  2322. 'PAGEUP' => 104,
  2323. 'LEFT' => 105,
  2324. 'RIGHT' => 106,
  2325. 'END' => 107,
  2326. 'DOWN' => 108,
  2327. 'PAGEDOWN' => 109,
  2328. 'INSERT' => 110,
  2329. 'DELETE' => 111,
  2330. 'MACRO' => 112,
  2331. 'MUTE' => 113,
  2332. 'VOLUMEDOWN' => 114,
  2333. 'VOLDOWN' => 114,
  2334. 'VOLUMEUP' => 115,
  2335. 'VOLUP' => 115,
  2336. 'POWER' => 116,
  2337. 'KPEQUAL' => 117,
  2338. 'KPPLUSMINUS' => 118,
  2339. 'PAUSE' => 119,
  2340. 'F21' => 120,
  2341. 'F22' => 121,
  2342. 'F23' => 122,
  2343. 'F24' => 123,
  2344. 'KPCOMMA' => 124,
  2345. 'LEFTMETA' => 125,
  2346. 'RIGHTMETA' => 126,
  2347. 'COMPOSE' => 127,
  2348. 'STOP' => 128,
  2349. 'AGAIN' => 129,
  2350. 'PROPS' => 130,
  2351. 'UNDO' => 131,
  2352. 'FRONT' => 132,
  2353. 'COPY' => 133,
  2354. 'OPEN' => 134,
  2355. 'PASTE' => 135,
  2356. 'FIND' => 136,
  2357. 'CUT' => 137,
  2358. 'HELP' => 138,
  2359. 'MENU' => 139,
  2360. 'CALC' => 140,
  2361. 'SETUP' => 141,
  2362. 'SLEEP' => 142,
  2363. 'WAKEUP' => 143,
  2364. 'FILE' => 144,
  2365. 'SENDFILE' => 145,
  2366. 'DELETEFILE' => 146,
  2367. 'XFER' => 147,
  2368. 'PROG1' => 148,
  2369. 'PROG2' => 149,
  2370. 'WWW' => 150,
  2371. 'MSDOS' => 151,
  2372. 'COFFEE' => 152,
  2373. 'DIRECTION' => 153,
  2374. 'CYCLEWINDOWS' => 154,
  2375. 'MAIL' => 155,
  2376. 'BOOKMARKS' => 156,
  2377. 'COMPUTER' => 157,
  2378. 'BACK' => 158,
  2379. 'FORWARD' => 159,
  2380. 'CLOSECD' => 160,
  2381. 'EJECTCD' => 161,
  2382. 'EJECTCLOSECD' => 162,
  2383. 'NEXTSONG' => 163,
  2384. 'PLAYPAUSE' => 164,
  2385. 'PREVIOUSSONG' => 165,
  2386. 'STOPCD' => 166,
  2387. 'RECORD' => 167,
  2388. 'REWIND' => 168,
  2389. 'PHONE' => 169,
  2390. 'ISO' => 170,
  2391. 'CONFIG' => 171,
  2392. 'HOMEPAGE' => 172,
  2393. 'REFRESH' => 173,
  2394. 'EXIT' => 174,
  2395. 'MOVE' => 175,
  2396. 'EDIT' => 176,
  2397. 'SCROLLUP' => 177,
  2398. 'SCROLLDOWN' => 178,
  2399. 'KPLEFTPAREN' => 179,
  2400. 'KPRIGHTPAREN' => 180,
  2401. 'INTL1' => 181,
  2402. 'INTL2' => 182,
  2403. 'INTL3' => 183,
  2404. 'INTL4' => 184,
  2405. 'INTL5' => 185,
  2406. 'INTL6' => 186,
  2407. 'INTL7' => 187,
  2408. 'INTL8' => 188,
  2409. 'INTL9' => 189,
  2410. 'LANG1' => 190,
  2411. 'LANG2' => 191,
  2412. 'LANG3' => 192,
  2413. 'LANG4' => 193,
  2414. 'LANG5' => 194,
  2415. 'LANG6' => 195,
  2416. 'LANG7' => 196,
  2417. 'LANG8' => 197,
  2418. 'LANG9' => 198,
  2419. 'PLAYCD' => 200,
  2420. 'PAUSECD' => 201,
  2421. 'PROG3' => 202,
  2422. 'PROG4' => 203,
  2423. 'SUSPEND' => 205,
  2424. 'CLOSE' => 206,
  2425. 'PLAY' => 207,
  2426. 'FASTFORWARD' => 208,
  2427. 'BASSBOOST' => 209,
  2428. 'PRINT' => 210,
  2429. 'HP' => 211,
  2430. 'CAMERA' => 212,
  2431. 'SOUND' => 213,
  2432. 'QUESTION' => 214,
  2433. 'EMAIL' => 215,
  2434. 'CHAT' => 216,
  2435. 'SEARCH' => 217,
  2436. 'CONNECT' => 218,
  2437. 'FINANCE' => 219,
  2438. 'SPORT' => 220,
  2439. 'SHOP' => 221,
  2440. 'ALTERASE' => 222,
  2441. 'CANCEL' => 223,
  2442. 'BRIGHTNESSDOWN' => 224,
  2443. 'BRIGHTNESSUP' => 225,
  2444. 'MEDIA' => 226,
  2445. 'UNKNOWN' => 240,
  2446. 'BTN_0' => 256,
  2447. 'BTN_1' => 257,
  2448. 'OK' => 352,
  2449. 'SELECT' => 353,
  2450. 'GOTO' => 354,
  2451. 'CLEAR' => 355,
  2452. 'POWER2' => 356,
  2453. 'OPTION' => 357,
  2454. 'INFO' => 358,
  2455. 'TIME' => 359,
  2456. 'VENDOR' => 360,
  2457. 'ARCHIVE' => 361,
  2458. 'PROGRAM' => 362,
  2459. 'CHANNEL' => 363,
  2460. 'FAVORITES' => 364,
  2461. 'EPG' => 365,
  2462. 'PVR' => 366,
  2463. 'MHP' => 367,
  2464. 'LANGUAGE' => 368,
  2465. 'TITLE' => 369,
  2466. 'SUBTITLE' => 370,
  2467. 'ANGLE' => 371,
  2468. 'ZOOM' => 372,
  2469. 'MODE' => 373,
  2470. 'KEYBOARD' => 374,
  2471. 'SCREEN' => 375,
  2472. 'PC' => 376,
  2473. 'TV' => 377,
  2474. 'TV2' => 378,
  2475. 'VCR' => 379,
  2476. 'VCR2' => 380,
  2477. 'SAT' => 381,
  2478. 'SAT2' => 382,
  2479. 'CD' => 383,
  2480. 'TAPE' => 384,
  2481. 'RADIO' => 385,
  2482. 'TUNER' => 386,
  2483. 'PLAYER' => 387,
  2484. 'TEXT' => 388,
  2485. 'DVD' => 389,
  2486. 'AUX' => 390,
  2487. 'MP3' => 391,
  2488. 'AUDIO' => 392,
  2489. 'VIDEO' => 393,
  2490. 'DIRECTORY' => 394,
  2491. 'LIST' => 395,
  2492. 'MEMO' => 396,
  2493. 'CALENDAR' => 397,
  2494. 'RED' => 398,
  2495. 'GREEN' => 399,
  2496. 'YELLOW' => 400,
  2497. 'BLUE' => 401,
  2498. 'CHANNELUP' => 402,
  2499. 'CHANUP' => 402,
  2500. 'CHANNELDOWN' => 403,
  2501. 'CHANDOWN' => 403,
  2502. 'FIRST' => 404,
  2503. 'LAST' => 405,
  2504. 'AB' => 406,
  2505. 'NEXT' => 407,
  2506. 'RESTART' => 408,
  2507. 'SLOW' => 409,
  2508. 'SHUFFLE' => 410,
  2509. 'BREAK' => 411,
  2510. 'PREVIOUS' => 412,
  2511. 'DIGITS' => 413,
  2512. 'TEEN' => 414,
  2513. 'TWEN' => 415,
  2514. 'DEL_EOL' => 448,
  2515. 'DEL_EOS' => 449,
  2516. 'INS_LINE' => 450,
  2517. 'DEL_LINE' => 451,
  2518. 'ASCII' => 510,
  2519. 'MAX' => 511
  2520. };
  2521. if ( defined( $commands->{$command} ) ) {
  2522. return $commands->{$command};
  2523. }
  2524. elsif ( $command eq "GetRemotecontrolCommands" ) {
  2525. return $commands;
  2526. }
  2527. else {
  2528. return "";
  2529. }
  2530. }
  2531. 1;
  2532. =pod
  2533. =item device
  2534. =item summary control for ENIGMA2 based receivers via network connection
  2535. =item summary_DE Steuerung von ENIGMA2 basierte Receiver &uuml;ber das Netzwerk
  2536. =begin html
  2537. <p>
  2538. <a name="ENIGMA2" id="ENIGMA2"></a>
  2539. </p>
  2540. <h3>
  2541. ENIGMA2
  2542. </h3>
  2543. <ul>
  2544. <a name="ENIGMA2define" id="ENIGMA2define"></a> <b>Define</b>
  2545. <ul>
  2546. <code>define &lt;name&gt; ENIGMA2 &lt;ip-address-or-hostname&gt; [[[[&lt;port&gt;] [&lt;poll-interval&gt;]] [&lt;http-user&gt;]] [&lt;http-password&gt;]]</code><br>
  2547. <br>
  2548. This module controls ENIGMA2 based devices like Dreambox or VUplus receiver via network connection.<br>
  2549. <br>
  2550. Defining an ENIGMA2 device will schedule an internal task (interval can be set with optional parameter &lt;poll-interval&gt; in seconds, if not set, the value is 45 seconds), which periodically reads the status of the device and triggers notify/filelog commands.<br>
  2551. <br>
  2552. Example:<br>
  2553. <ul>
  2554. <code>define SATReceiver ENIGMA2 192.168.0.10<br>
  2555. <br>
  2556. # With custom port<br>
  2557. define SATReceiver ENIGMA2 192.168.0.10 8080<br>
  2558. <br>
  2559. # With custom interval of 20 seconds<br>
  2560. define SATReceiver ENIGMA2 192.168.0.10 80 20<br>
  2561. <br>
  2562. # With HTTP user credentials<br>
  2563. define SATReceiver ENIGMA2 192.168.0.10 80 20 root secret</code>
  2564. </ul>
  2565. </ul><br>
  2566. <br>
  2567. <a name="ENIGMA2set" id="ENIGMA2set"></a> <b>Set</b>
  2568. <ul>
  2569. <code>set &lt;name&gt; &lt;command&gt; [&lt;parameter&gt;]</code><br>
  2570. <br>
  2571. Currently, the following commands are defined.<br>
  2572. <ul>
  2573. <li>
  2574. <b>on</b> &nbsp;&nbsp;-&nbsp;&nbsp; powers on the device and send a WoL magic package if needed
  2575. </li>
  2576. <li>
  2577. <b>off</b> &nbsp;&nbsp;-&nbsp;&nbsp; turns the device in standby mode
  2578. </li>
  2579. <li>
  2580. <b>toggle</b> &nbsp;&nbsp;-&nbsp;&nbsp; switch between on and off
  2581. </li>
  2582. <li>
  2583. <b>shutdown</b> &nbsp;&nbsp;-&nbsp;&nbsp; turns the device in deepstandby mode
  2584. </li>
  2585. <li>
  2586. <b>reboot</b> &nbsp;&nbsp;-&nbsp;&nbsp;reboots the device
  2587. </li>
  2588. <li>
  2589. <b>restartGui</b> &nbsp;&nbsp;-&nbsp;&nbsp;restarts the GUI / ENIGMA2 process
  2590. </li>
  2591. <li>
  2592. <b>channel</b> channel,0...999,sRef &nbsp;&nbsp;-&nbsp;&nbsp; zap to specific channel or service reference
  2593. </li>
  2594. <li>
  2595. <b>channelUp</b> &nbsp;&nbsp;-&nbsp;&nbsp; zap to next channel
  2596. </li>
  2597. <li>
  2598. <b>channelDown</b> &nbsp;&nbsp;-&nbsp;&nbsp; zap to previous channel
  2599. </li>
  2600. <li>
  2601. <b>volume</b> 0...100 &nbsp;&nbsp;-&nbsp;&nbsp; set the volume level in percentage
  2602. </li>
  2603. <li>
  2604. <b>volumeUp</b> &nbsp;&nbsp;-&nbsp;&nbsp; increases the volume level
  2605. </li>
  2606. <li>
  2607. <b>volumeDown</b> &nbsp;&nbsp;-&nbsp;&nbsp; decreases the volume level
  2608. </li>
  2609. <li>
  2610. <b>mute</b> on,off,toggle &nbsp;&nbsp;-&nbsp;&nbsp; controls volume mute
  2611. </li>
  2612. <li>
  2613. <b>play</b> &nbsp;&nbsp;-&nbsp;&nbsp; starts/resumes playback
  2614. </li>
  2615. <li>
  2616. <b>pause</b> &nbsp;&nbsp;-&nbsp;&nbsp; pauses current playback or enables timeshift
  2617. </li>
  2618. <li>
  2619. <b>stop</b> &nbsp;&nbsp;-&nbsp;&nbsp; stops current playback
  2620. </li>
  2621. <li>
  2622. <b>record</b> &nbsp;&nbsp;-&nbsp;&nbsp; starts recording of current channel
  2623. </li>
  2624. <li>
  2625. <b>input</b> tv,radio &nbsp;&nbsp;-&nbsp;&nbsp; switches between tv and radio mode
  2626. </li>
  2627. <li>
  2628. <b>statusRequest</b> &nbsp;&nbsp;-&nbsp;&nbsp; requests the current status of the device
  2629. </li>
  2630. <li>
  2631. <b>remoteControl</b> UP,DOWN,... &nbsp;&nbsp;-&nbsp;&nbsp; sends remote control commands; see remoteControl help for full command list<br />
  2632. Note: You may add the word "long" after the command to simulate a long key press.
  2633. </li>
  2634. <li>
  2635. <b>showText</b> text &nbsp;&nbsp;-&nbsp;&nbsp; sends info message to screen to be displayed for 8 seconds
  2636. </li>
  2637. <li>
  2638. <b>msg</b> yesno,info... &nbsp;&nbsp;-&nbsp;&nbsp; allows more complex messages as showText, see commands as listed below
  2639. </li>
  2640. </ul>
  2641. <ul>
  2642. <u>Note:</u> If you would like to restrict access to admin set-commands (-> statusRequest, reboot, restartGui, shutdown) you may set your FHEMWEB instance's attribute allowedCommands like 'set,set-user'.
  2643. The string 'set-user' will ensure only non-admin set-commands can be executed when accessing FHEM using this FHEMWEB instance.
  2644. </ul>
  2645. </ul><br>
  2646. <br>
  2647. <ul>
  2648. <u>Messaging</u><br>
  2649. <br>
  2650. <ul>
  2651. showText has predefined settings. If you would like to send more individual messages to your TV screen, the function msg can be used. For this application the following commands are available:<br>
  2652. <br>
  2653. <u>Type Selection:</u><br>
  2654. <ul>
  2655. <code>msg yesno<br>
  2656. msg info<br>
  2657. msg message<br>
  2658. msg attention<br></code>
  2659. </ul><br>
  2660. <br>
  2661. The following parameter are essentially needed after type specification:
  2662. <ul>
  2663. <code>msg &lt;TYPE&gt; &lt;TIMEOUT&gt; &lt;YOUR MESSAGETEXT&gt;<br></code>
  2664. </ul>
  2665. </ul>
  2666. </ul><br>
  2667. <br>
  2668. <a name="ENIGMA2get" id="ENIGMA2get"></a> <b>Get</b>
  2669. <ul>
  2670. <code>get &lt;name&gt; &lt;what&gt;</code><br>
  2671. <br>
  2672. Currently, the following commands are defined:<br>
  2673. <br>
  2674. <ul>
  2675. <code>channel<br>
  2676. currentMedia<br>
  2677. currentTitle<br>
  2678. mute<br>
  2679. nextTitle<br>
  2680. power<br>
  2681. providername<br>
  2682. servicevideosize<br>
  2683. input<br>
  2684. streamUrl<br>
  2685. volume<br></code>
  2686. </ul>
  2687. </ul><br>
  2688. <br>
  2689. <a name="ENIGMA2attr" id="ENIGMA2attr"></a> <b>Attributes</b><br>
  2690. <ul>
  2691. <ul>
  2692. <li>
  2693. <b>bouquet-tv</b> - service reference address where the favorite television bouquet can be found (initially set automatically during define)
  2694. </li>
  2695. <li>
  2696. <b>bouquet-radio</b> - service reference address where the favorite radio bouquet can be found (initially set automatically during define)
  2697. </li>
  2698. <li>
  2699. <b>disable</b> - Disable polling (true/false)
  2700. </li>
  2701. <li>
  2702. <b>http-method</b> - HTTP access method to be used; e.g. a FritzBox might need to use POST instead of GET (GET/POST)
  2703. </li>
  2704. <li>
  2705. <b>http-noshutdown</b> - Set FHEM-internal HttpUtils connection close behaviour (defaults=1)
  2706. </li>
  2707. <li>
  2708. <b>https</b> - Access box via secure HTTP (true/false)
  2709. </li>
  2710. <li>
  2711. <b>ignoreState</b> - Do not check for available device before sending commands to it (true/false)
  2712. </li>
  2713. <li>
  2714. <b>lightMode</b> - reduces regular queries (resulting in less functionality), e.g. for low performance devices. (true/false)
  2715. </li>
  2716. <li>
  2717. <b>macaddr</b> - manually set specific MAC address for device; overwrites value from reading "lanmac". (true/false)
  2718. </li>
  2719. <li>
  2720. <b>remotecontrol</b> - Explicitly set specific remote control unit format. This will only be considered for set-command <strong>remoteControl</strong> as of now.
  2721. </li>
  2722. <li>
  2723. <b>timeout</b> - Set different polling timeout in seconds (default=6)
  2724. </li>
  2725. <li>
  2726. <b>wakeupCmd</b> - Set a command to be executed when turning on an absent device. Can be an FHEM command or Perl command in {}. Available variables: ENIGMA2 device name -> $DEVICE, ENIGMA2 device MAC address -> $MACADDR (default=Wake-on-LAN)
  2727. </li>
  2728. </ul>
  2729. </ul><br>
  2730. <br>
  2731. <br>
  2732. <b>Generated Readings/Events:</b><br>
  2733. <ul>
  2734. <ul>
  2735. <li>
  2736. <b>acg</b> - Shows Automatic Gain Control value in percent; reflects overall signal quality strength
  2737. </li>
  2738. <li>
  2739. <b>apid</b> - Shows the audio process ID for current channel
  2740. </li>
  2741. <li>
  2742. <b>ber</b> - Shows Bit Error Rate for current channel
  2743. </li>
  2744. <li>
  2745. <b>channel</b> - Shows the service name of current channel or media file name; part of FHEM-4-AV-Devices compatibility
  2746. </li>
  2747. <li>
  2748. <b>currentMedia</b> - The service reference ID of current channel; part of FHEM-4-AV-Devices compatibility
  2749. </li>
  2750. <li>
  2751. <b>currentTitle</b> - Shows the title of the running event; part of FHEM-4-AV-Devices compatibility
  2752. </li>
  2753. <li>
  2754. <b>enigmaversion</b> - Shows the installed version of ENIGMA2
  2755. </li>
  2756. <li>
  2757. <b>eventcurrenttime</b> - Shows the current time of running event as UNIX timestamp
  2758. </li>
  2759. <li>
  2760. <b>eventcurrenttime_hr</b> - Shows the current time of running event in human-readable format
  2761. </li>
  2762. <li>
  2763. <b>eventcurrenttime_next</b> - Shows the current time of next event as UNIX timestamp
  2764. </li>
  2765. <li>
  2766. <b>eventcurrenttime_next_hr</b> - Shows the current time of next event in human-readable format
  2767. </li>
  2768. <li>
  2769. <b>eventdescription</b> - Shows the description of running event
  2770. </li>
  2771. <li>
  2772. <b>eventdescriptionextended</b> - Shows the extended description of running event
  2773. </li>
  2774. <li>
  2775. <b>eventdescriptionextended_next</b> - Shows the extended description of next event
  2776. </li>
  2777. <li>
  2778. <b>eventdescription_next</b> - Shows the description of next event
  2779. </li>
  2780. <li>
  2781. <b>evenduration</b> - Shows the total duration time of running event in seconds
  2782. </li>
  2783. <li>
  2784. <b>evenduration_hr</b> - Shows the total duration time of running event in human-readable format
  2785. </li>
  2786. <li>
  2787. <b>evenduration_next</b> - Shows the total duration time of next event in seconds
  2788. </li>
  2789. <li>
  2790. <b>evenduration_next_hr</b> - Shows the total duration time of next event in human-readable format
  2791. </li>
  2792. <li>
  2793. <b>eventname</b> - Shows the name of running event
  2794. </li>
  2795. <li>
  2796. <b>eventname_next</b> - Shows the name of next event
  2797. </li>
  2798. <li>
  2799. <b>eventremaining</b> - Shows the remaining duration time of running event in seconds
  2800. </li>
  2801. <li>
  2802. <b>eventremaining_hr</b> - Shows the remaining duration time of running event in human-readable format
  2803. </li>
  2804. <li>
  2805. <b>eventremaining_next</b> - Shows the remaining duration time of next event in seconds
  2806. </li>
  2807. <li>
  2808. <b>eventremaining_next_hr</b> - Shows the remaining duration time of next event in human-readable format
  2809. </li>
  2810. <li>
  2811. <b>eventstart</b> - Shows the starting time of running event as UNIX timestamp
  2812. </li>
  2813. <li>
  2814. <b>eventstart_hr</b> - Shows the starting time of running event in human readable format
  2815. </li>
  2816. <li>
  2817. <b>eventstart_next</b> - Shows the starting time of next event as UNIX timestamp
  2818. </li>
  2819. <li>
  2820. <b>eventstart_next_hr</b> - Shows the starting time of next event in human readable format
  2821. </li>
  2822. <li>
  2823. <b>eventtitle</b> - Shows the title of the running event
  2824. </li>
  2825. <li>
  2826. <b>eventtitle_next</b> - Shows the title of the next event
  2827. </li>
  2828. <li>
  2829. <b>fpversion</b> - Shows the firmware version for the front processor
  2830. </li>
  2831. <li>
  2832. <b>hddX_capacity</b> - Shows the total capacity of the installed hard drive in GB
  2833. </li>
  2834. <li>
  2835. <b>hddX_free</b> - Shows the free capacity of the installed hard drive in GB
  2836. </li>
  2837. <li>
  2838. <b>hddX_model</b> - Shows hardware details for the installed hard drive
  2839. </li>
  2840. <li>
  2841. <b>imageversion</b> - Shows the version for the installed software image
  2842. </li>
  2843. <li>
  2844. <b>input</b> - Shows currently used input; part of FHEM-4-AV-Devices compatibility
  2845. </li>
  2846. <li>
  2847. <b>iswidescreen</b> - Indicates widescreen format - 0=off 1=on
  2848. </li>
  2849. <li>
  2850. <b>lanmac</b> - Shows the device MAC address
  2851. </li>
  2852. <li>
  2853. <b>model</b> - Shows details about the device hardware
  2854. </li>
  2855. <li>
  2856. <b>mute</b> - Reports the mute status of the device (can be "on" or "off")
  2857. </li>
  2858. <li>
  2859. <b>nextTitle</b> - Shows the title of the next event; part of FHEM-4-AV-Devices compatibility
  2860. </li>
  2861. <li>
  2862. <b>onid</b> - The ON ID
  2863. </li>
  2864. <li>
  2865. <b>pcrpid</b> - The PCR process ID
  2866. </li>
  2867. <li>
  2868. <b>pmtpid</b> - The PMT process ID
  2869. </li>
  2870. <li>
  2871. <b>power</b> - Reports the power status of the device (can be "on" or "off")
  2872. </li>
  2873. <li>
  2874. <b>presence</b> - Reports the presence status of the receiver (can be "absent" or "present"). In case of an absent device, control is basically limited to turn it on again. This will only work if the device supports Wake-On-LAN packages, otherwise command "on" will have no effect.
  2875. </li>
  2876. <li>
  2877. <b>providername</b> - Service provider of current channel
  2878. </li>
  2879. <li>
  2880. <b>recordings</b> - Number of active recordings
  2881. </li>
  2882. <li>
  2883. <b>recordingsX_name</b> - name of active recording no. X
  2884. </li>
  2885. <li>
  2886. <b>recordingsX_servicename</b> - servicename of active recording no. X
  2887. </li>
  2888. <li>
  2889. <b>recordings_next</b> - Shows the time of next recording as UNIX timestamp
  2890. </li>
  2891. <li>
  2892. <b>recordings_next_hr</b> - Shows the time of next recording as human-readable format
  2893. </li>
  2894. <li>
  2895. <b>recordings_next_counter</b> - Shows the time until next recording starts in seconds
  2896. </li>
  2897. <li>
  2898. <b>recordings_next_counter_hr</b> - Shows the time until next recording starts human-readable format
  2899. </li>
  2900. <li>
  2901. <b>recordings_next_name</b> - name of next recording
  2902. </li>
  2903. <li>
  2904. <b>recordings_next_servicename</b> - servicename of next recording
  2905. </li>
  2906. <li>
  2907. <b>recordings_error</b> - counter for failed recordings in timerlist
  2908. </li>
  2909. <li>
  2910. <b>recordings_finished</b> - counter for finished recordings in timerlist
  2911. </li>
  2912. <li>
  2913. <b>servicename</b> - Name for current channel
  2914. </li>
  2915. <li>
  2916. <b>servicereference</b> - The service reference ID of current channel
  2917. </li>
  2918. <li>
  2919. <b>servicevideosize</b> - Video resolution for current channel
  2920. </li>
  2921. <li>
  2922. <b>sid</b> - The S-ID
  2923. </li>
  2924. <li>
  2925. <b>snr</b> - Shows Signal to Noise for current channel in percent
  2926. </li>
  2927. <li>
  2928. <b>snrdb</b> - Shows Signal to Noise in dB
  2929. </li>
  2930. <li>
  2931. <b>state</b> - Reports current power state and an absence of the device (can be "on", "off" or "absent")
  2932. </li>
  2933. <li>
  2934. <b>tsid</b> - The TS ID
  2935. </li>
  2936. <li>
  2937. <b>tuner_X</b> - Details about the used tuner hardware
  2938. </li>
  2939. <li>
  2940. <b>txtpid</b> - The TXT process ID
  2941. </li>
  2942. <li>
  2943. <b>videoheight</b> - Height of the video resolution for current channel
  2944. </li>
  2945. <li>
  2946. <b>videowidth</b> - Width of the video resolution for current channel
  2947. </li>
  2948. <li>
  2949. <b>volume</b> - Reports current volume level of the receiver in percentage values (between 0 and 100 %)
  2950. </li>
  2951. <li>
  2952. <b>vpid</b> - The Video process ID
  2953. </li>
  2954. <li>
  2955. <b>webifversion</b> - Type and version of the used web interface
  2956. </li>
  2957. </ul>
  2958. </ul>
  2959. </ul>
  2960. =end html
  2961. =begin html_DE
  2962. <p>
  2963. <a name="ENIGMA2" id="ENIGMA2"></a>
  2964. </p>
  2965. <h3>
  2966. ENIGMA2
  2967. </h3>
  2968. <ul>
  2969. Eine deutsche Version der Dokumentation ist derzeit nicht vorhanden. Die englische Version ist hier zu finden:
  2970. </ul>
  2971. <ul>
  2972. <a href='http://fhem.de/commandref.html#ENIGMA2'>ENIGMA2</a>
  2973. </ul>
  2974. =end html_DE
  2975. =cut