70_ENIGMA2.pm 119 KB

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