| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683 |
- # $Id: 71_PHILIPS_AUDIO.pm 14036 2017-04-19 18:30:30Z ra666ack $
- ##############################################################################
- #
- # 71_PHILIPS_AUDIO.pm
- #
- # An FHEM Perl module for controlling Philips Audio Equipment connected to
- # local network such as MCi, Streamium and Fidelio devices.
- # The module provides basic functionality accessible through the port 8889
- # of the device: (http://<device_ip>:8889/index)
- # e.g. AW9000, NP3500, NP3700, NP3900
- #
- # Copyright by ra666ack
- # (e-mail: ra666ack at g**glemail d*t c*m)
- #
- # This file is part of fhem.
- #
- # Fhem is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 2 of the License, or
- # (at your option) any later version.
- #
- # Fhem is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with fhem. If not, see <http://www.gnu.org/licenses/>.
- #
- ##############################################################################
- package main;
- use strict;
- use warnings;
- use Time::HiRes qw(gettimeofday sleep);
- use Time::Piece;
- use POSIX qw{strftime};
- use HttpUtils;
- sub PHILIPS_AUDIO_Initialize
- {
- my ($hash) = @_;
- $hash->{DefFn} = "PHILIPS_AUDIO_Define";
- $hash->{GetFn} = "PHILIPS_AUDIO_Get";
- $hash->{SetFn} = "PHILIPS_AUDIO_Set";
- $hash->{AttrFn} = "PHILIPS_AUDIO_Attr";
- $hash->{UndefFn} = "PHILIPS_AUDIO_Undefine";
- $hash->{AttrList} = "do_not_notify:0,1 ".
- "disable:0,1 ".
- "autoGetPresets:0,1 ".
- "autoGetFavorites:0,1 ".
- "httpBufferTimeout ".
- "maxListItems ".
- "model ".
- "playerBrowsingTimeout ".
- "requestTimeout ".
- "$readingFnAttributes";
- return;
- }
- sub PHILIPS_AUDIO_GetStatus
- {
- my ($hash, $local) = @_;
- my $name = $hash->{NAME};
- my $power;
- $local = 0 unless(defined($local));
- return if((!defined($hash->{IP_ADDRESS})) or (!defined($hash->{helper}{OFF_INTERVAL})) or (!defined($hash->{helper}{ON_INTERVAL})));
- my $device = $hash->{IP_ADDRESS};
-
- # First run
- $hash->{helper}{networkRequest} = "idle" if (not defined($hash->{helper}{networkRequest}));
-
- # Try to get additional info from the device.
- # Only if device already implemented.
- # Otherwise possible timeout due to wrong ports and device description links
- if(not defined($hash->{helper}{dInfo}{UUID}))
- {
- if (grep {$_ eq $hash->{MODEL}} @{$hash->{helper}{DevDescImplementedModels}})
- {
- PHILIPS_AUDIO_getMediaRendererDesc($hash);
- }
- }
-
- if (not defined($hash->{helper}{playerState}))
- {
- # First run. Go to index.
- $hash->{helper}{playerState} = "home";
- readingsSingleUpdate($hash, "playerState", "home", 1);
- PHILIPS_AUDIO_SendCommand($hash, "/index", "","home", "noArg");
- PHILIPS_AUDIO_ResetTimer($hash); # getStatus
- return;
- }
-
- if($hash->{helper}{playerState} eq "home")
- {
- # Check if device playing. Might by activated by the remote control or app.
- # If not, the device returns 'NOTHING';
- PHILIPS_AUDIO_SendCommand($hash, "/nowplay", "","nowplay", "noArg");
-
- # Heartbeat
- #PHILIPS_AUDIO_SendCommand($hash, "/HOMESTATUS", "","homestatus", "noArg");
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "input", "-");
- readingsBulkUpdate($hash, "playerState", "home");
- readingsBulkUpdate($hash, "playerPlaying", "no");
- readingsEndUpdate($hash, 1);
- }
- elsif($hash->{helper}{playerState} eq "browsing")
- {
- # Do nothing and check for inactivity duration
-
- $hash->{helper}{playerBrowsingTimeout} = 0 if(not defined ($hash->{helper}{playerBrowsingTimeout}));
-
- $hash->{helper}{playerBrowsingTimeout} += $hash->{helper}{ON_INTERVAL};
-
- # reset browsing state after 3 minutes inactivity in order to update the readings automatically again
- if($hash->{helper}{playerBrowsingTimeout} >= int(AttrVal($name, "playerBrowsingTimeout", 180)))
- {
- $hash->{helper}{playerState} = "home";
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "input", "-");
- readingsBulkUpdate($hash, "playerState", "home");
- readingsBulkUpdate($hash, "playerPlaying", "no");
- readingsEndUpdate($hash, 1);
- $hash->{helper}{playerBrowsingTimeout} = 0;
- }
- }
- elsif($hash->{helper}{playerState} eq "playing")
- {
- PHILIPS_AUDIO_SendCommand($hash, "/ELAPSE", "","elapse", "noArg");
- }
-
- # Check for Presets availability
- if
- (
- (not defined($hash->{READINGS}{"totalPresets"})) and
- (ReadingsVal($name, "presence", "no") eq "present") and
- (AttrVal($name, "autoGetPresets", "0") eq "1")
- )
- {
- readingsSingleUpdate($hash, "Reading_presets" , "May take some time...", 1);
- # Hierarchichal navigation through the contents mandatory
- $hash->{helper}{cmdStep} = 1;
- PHILIPS_AUDIO_SendCommand($hash, "/index", "", "getPresets", "noArg") if((ReadingsVal($name, "playerListStatus", "ready") eq "ready") and (ReadingsVal($name, "readingPresets", "no") eq "no"));
- PHILIPS_AUDIO_ResetTimer($hash, 10); # Scan takes approx 8 sec.
- return;
- }
-
- # Check for Favorites availability
- if
- (
- (not defined($hash->{READINGS}{"totalFavorites"})) and
- (ReadingsVal($name, "presence", "no") eq "present") and
- (AttrVal($name, "autoGetFavorites", "0") eq "1")
- )
- {
- readingsSingleUpdate($hash, "Reading_favorites" , "May take some time...", 1);
- # Hierarchichal navigation through the contents mandatory
- $hash->{helper}{cmdStep} = 1;
- PHILIPS_AUDIO_SendCommand($hash, "/index", "", "getFavorites", "noArg") if((ReadingsVal($name, "playerListStatus", "ready") eq "ready") and (ReadingsVal($name, "readingFavorites", "no") eq "no"));
- PHILIPS_AUDIO_ResetTimer($hash, 10); # Scan takes approx 8 sec.
- return;
- }
-
- PHILIPS_AUDIO_ResetTimer($hash) if(not ($local == 1)); # getStatus
- return;
- }
- sub PHILIPS_AUDIO_Get
- {
- my ($hash, @a) = @_;
- my $what = $a[1];
- my $return;
-
- my $name = $hash->{NAME};
-
- my $address = $hash->{IP_ADDRESS};
- $hash->{IP_ADDRESS} = $address;
-
- return "Argument missing." if(int(@a) < 2);
-
- if($what eq "reading")
- {
- if(exists($hash->{READINGS}{$a[2]}))
- {
- if(defined($hash->{READINGS}{$a[2]}))
- {
- return $hash->{READINGS}{$a[2]}{VAL};
- }
- else
- {
- return "No such reading: $what";
- }
- }
- }
- elsif($what eq "deviceInfo")
- {
- return "Device info:\n\n".
- join("\n", map {sprintf("%-17s: %-17s", $_, $hash->{helper}{dInfo}{$_})} sort keys %{$hash->{helper}{dInfo}});
- }
- else
- {
- $return = "Unknown argument $what, choose one of"
- ." deviceInfo:noArg"
- ." reading:".(join(",",(sort keys %{$hash->{READINGS}})));
-
- return $return;
- }
- }
- sub PHILIPS_AUDIO_Set
- {
- my ($hash, @a) = @_;
- my $name = $hash->{NAME};
- my $port = $hash->{PORT};
- my $address = $hash->{IP_ADDRESS};
-
- if(not defined($hash->{MODEL}))
- {
- return "Please provide the model information as argument.";
- }
-
- return "No Argument given" if(!defined($a[1]));
- my $what = $a[1];
- my $usage = "";
-
- my $model = $hash->{MODEL};
-
- $hash->{helper}{dInfo}{MODEL} = $model;
- $hash->{helper}{dInfo}{NAME} = $name;
- $hash->{helper}{dInfo}{PORT} = $port;
- $hash->{helper}{dInfo}{IP_ADDRESS} = $address;
- $usage = "Unknown argument $what, choose one of".
- " volumeStraight:slider,0,1,64 ".
- " volume:slider,0,1,100 ".
- " volumeUp:noArg ".
- " volumeDown:noArg ".
- " standbyButton:noArg ".
- " player:next,prev,play-pause,stop ".
- " shuffle:on,off ".
- " input:---,".
-
- ((uc($model) eq "AW9000") ? "analogAux," : ""). # Input implemented in AW9000 only
- ((uc($model) eq "AW9000") ? "digital1Coaxial," : ""). # Input implemented in AW9000 only
- ((uc($model) eq "AW9000") ? "digital2Optical," : ""). # Input implemented in AW9000 only
-
- # Input not implemented in the AW9000. Only as DLNA renderer
- ((uc($model) ne "AW9000") ? "mediaLibrary," : "").
-
- "internetRadio,onlineServices,mp3Link ". # Available in all devices
- #" statusRequest:noArg".
- " getPresets:noArg".
- " getFavorites:noArg".
- " getMediaRendererDesc:noArg".
- " favoriteAdd:noArg".
- " favoriteRemove:noArg".
- " repeat:single,all,off".
- #" home:noArg".
- " mute:on,off ";
- my @favoriteList;
- my @favoriteNumber;
- foreach my $readings (keys % {$hash->{READINGS}})
- {
- push @favoriteList,$1."_".substr($hash->{READINGS}{$readings}{VAL}, 0, 25) if($readings =~ m/^.inetRadioFavorite_(..)/);
- push @favoriteNumber, $1 if($readings =~ m/^.inetRadioFavorite_(..)/);
- }
-
- (s/\*/\[asterisk\]/g) for @favoriteList; # '*' not shown correctly
- (s/#/\[hash\]/g) for @favoriteList; # '#' not shown correctly
- (s/[\\]//g) for @favoriteList;
- (s/[ :;,']/_/g) for @favoriteList; # Replace not allowed characters
-
- my @presetList;
- my @presetNumber;
- foreach my $readings (keys % {$hash->{READINGS}})
- {
- push @presetList, $1."_".substr($hash->{READINGS}{$readings}{VAL}, 0, 25) if($readings =~ m/^.inetRadioPreset_(..)/);
- push @presetNumber, $1 if($readings =~ m/^.inetRadioPreset_(..)/);
- }
-
- (s/\*/\[asterisk\]/g) for @presetList; # '*' not shown correctly
- (s/#/\[hash\]/g) for @presetList; # '#' not shown correctly
- (s/[\\]//g) for @presetList; # Replace \
- (s/[ :;,']/_/g) for @presetList; # Replace not allowed characters
-
- $usage .= "selectFavorite:" .join(",",("---",(sort @favoriteList))) . " ";
- $usage .= "selectPreset:" .join(",",("---",(sort @presetList))) . " ";
- $usage .= "selectPresetByNumber:" .join(",",("---",(sort @presetNumber))) . " ";
- $usage .= "selectFavoriteByNumber:".join(",",("---",(sort @favoriteNumber))) . " ";
- # Direct stream selection if any
-
- my @selectStream;
-
- for(my $lvl = 1; $lvl < int(ReadingsVal($name, ".listDepthLevel", "1") - 1); $lvl++)
- {
- my $listLevelName = ReadingsVal($name, ".lvl_".$lvl."_name", "");
- push @selectStream, "lvl_".$lvl."_".$listLevelName;
- }
-
- foreach my $readings (keys % {$hash->{READINGS}})
- {
- push @selectStream,$1."_".substr($hash->{READINGS}{$readings}{VAL}, 0, 25) if($readings =~ m/^listItem_(...)/);
- }
-
- @selectStream = sort map{s/\*/\[asterisk\]/g;$_;} grep/._..*$/, @selectStream; # Replace *
- @selectStream = sort map{s/#/\[hash\]/g;$_;} grep/._..*$/, @selectStream; # Replace #
- @selectStream = sort map{s/[\\]//g;$_;} grep/._..*$/, @selectStream; # Replace not allowed characters
- @selectStream = sort map{s/[ :;,']/_/g;$_;} grep/._..*$/, @selectStream; # Replace not allowed characters
-
- $usage .= "selectStream:".join(",",("---",(sort @selectStream))) . " ";
-
- Log3 $name, 5, "PHILIPS_AUDIO ($name) - set ".join(" ", @a);
-
- # External Command. Not from buffer timer.
- $hash->{helper}{fromSendCommandBuffer} = 0;
-
- if($what =~ /input|selectStream|selectPreset|selectFavorite/)
- {
- # GetStatus while manual operation causes the device to stuck. Supress.
- # Change device state to "browsing" in order to suppress automatic update
- $hash->{helper}{playerState} = "browsing";
- $hash->{helper}{manualOperation} = 1;
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "playerState", "browsing");
- readingsBulkUpdate($hash, ".manualOperation", "yes", 1);
- readingsEndUpdate($hash, 1);
- # Reset browsing timeout
- $hash->{helper}{playerBrowsingTimeout} = 0;
- }
- if($what eq "standbyButton")
- {
- readingsSingleUpdate($hash, "input", "-", 1);
- PHILIPS_AUDIO_SendCommand($hash, "/CTRL\$STANDBY", "",$what, "noArg");
- }
- elsif($what eq "getMediaRendererDesc")
- {
- PHILIPS_AUDIO_getMediaRendererDesc($hash);
- }
- elsif($what eq "input")
- {
- if ($a[2] =~ /analogAux|mp3Link|digital1Coaxial|digital2Optical/)
- {
- # Delete List related readings
- delete $hash->{READINGS}{$_} foreach (grep /list/, keys %{$hash->{READINGS}});
- # Delete player related readings
- delete $hash->{READINGS}{$_} foreach (grep /player/, keys %{$hash->{READINGS}});
- }
-
- if($a[2] eq "analogAux")
- {
- readingsSingleUpdate($hash, "input", "Aux-in (analog)", 1);
- PHILIPS_AUDIO_SendCommand($hash, "/aux", "",$what, $a[2]);
- }
- elsif($a[2] eq "mp3Link")
- {
-
- $hash->{helper}{playerState} = "home";
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "input", "MP3-Link");
- readingsBulkUpdate($hash, "playerState", "home");
- readingsEndUpdate($hash, 1);
-
- if(uc($model) eq "AW9000")
- {
- PHILIPS_AUDIO_SendCommand($hash, "/mp3link", "", $what, $a[2]);
- }
- else
- {
- PHILIPS_AUDIO_SendCommand($hash, "/aux", "", $what, $a[2]);
- }
- }
- elsif($a[2] eq "digital1Coaxial")
- {
- $hash->{helper}{playerState} = "home";
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "input", "Digital-in 1 (coaxial)");
- readingsBulkUpdate($hash, "playerState", "home");
- readingsEndUpdate($hash, 1);
-
- PHILIPS_AUDIO_SendCommand($hash, "/digin_coaxial", "",$what, $a[2]);
-
- }
- elsif($a[2] eq "digital2Optical")
- {
- $hash->{helper}{playerState} = "home";
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "input", "Digital-in 2 (optical)");
- readingsBulkUpdate($hash, "playerState", "home");
- readingsEndUpdate($hash, 1);
-
- PHILIPS_AUDIO_SendCommand($hash, "/digin_optical", "",$what, $a[2]);
- }
- elsif($a[2] eq "mediaLibrary")
- {
- readingsSingleUpdate($hash, "playerListStatus", "busy", 1);
- #readingsSingleUpdate($hash, "input", "Media Library", 1);
- PHILIPS_AUDIO_SendCommand($hash, "/nav\$02\$01\$001\$0", "", $what, $a[2]);
- }
- elsif($a[2] eq "internetRadio")
- {
- readingsSingleUpdate($hash, "playerListStatus", "busy", 1);
- #readingsSingleUpdate($hash, "input", "Internet Radio", 1);
- PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$01\$001\$0", "",$what, $a[2]);
- }
- elsif($a[2] eq "onlineServices")
- {
- readingsSingleUpdate($hash, "playerListStatus", "busy", 1);
- #readingsSingleUpdate($hash, "input", "Online Services", 1);
- PHILIPS_AUDIO_SendCommand($hash, "/nav\$09\$01\$001\$0", "", $what, $a[2]);
- }
- else
- {
- return $usage;
- }
- }
- elsif($what eq "home")
- {
- readingsSingleUpdate($hash, "playerListStatus", "busy", 1);
- $hash->{header}{httpHeaderRefer} = "Upgrade-Insecure-Requests: 1\r\n";
- PHILIPS_AUDIO_SendCommand($hash, "/index", "",$what, "noArg");
- }
- elsif($what eq "shuffle")
- {
- if($a[2] eq "on")
- {
- readingsSingleUpdate($hash, "playerShuffle", "on", 1);
- PHILIPS_AUDIO_SendCommand($hash, "/MODE\$SHUFFLE_ON", "",$what, $a[2]);
- }
- elsif($a[2] eq "off")
- {
- readingsSingleUpdate($hash, "playerShuffle", "off", 1);
- PHILIPS_AUDIO_SendCommand($hash, "/MODE\$SHUFFLE_OFF", "",$what, $a[2]);
- }
- else
- {
- return $usage;
- }
- }
- elsif($what eq "repeat")
- {
- if($a[2] eq "single")
- {
- readingsSingleUpdate($hash, "playerRepeat", "single", 1);
- PHILIPS_AUDIO_SendCommand($hash, "/MODE\$REPEAT_SINGLE", "",$what, $a[2]);
- }
- elsif($a[2] eq "all")
- {
- readingsSingleUpdate($hash, "playerRepeat", "all", 1);
- PHILIPS_AUDIO_SendCommand($hash, "/MODE\$REPEAT_ALL", "",$what, $a[2]);
- }
- elsif($a[2] eq "off")
- {
- readingsSingleUpdate($hash, "playerRepeat", "off", 1);
- PHILIPS_AUDIO_SendCommand($hash, "/MODE\$REPEAT_OFF", "",$what, $a[2]);
- }
- else
- {
- return $usage;
- }
- }
- elsif($what eq "statusRequest")
- {
- PHILIPS_AUDIO_SendCommand($hash, "/nowplay", "","nowplay", "noArg");
- }
- elsif($what eq "favoriteAdd")
- {
- PHILIPS_AUDIO_SendCommand($hash, "/CTRL\$ADD2FAV", "",$what, "noArg");
- }
- elsif($what eq "favoriteRemove")
- {
- PHILIPS_AUDIO_SendCommand($hash, "/CTRL\$REMFAV", "",$what, "noArg");
- }
- elsif($what eq "mute")
- {
- if($a[2] eq "on")
- {
- readingsSingleUpdate($hash, "mute", "on", 1);
- PHILIPS_AUDIO_SendCommand($hash, "/VOLUME\$MUTE", "",$what, "noArg");
- }
- elsif($a[2] eq "off")
- {
- readingsSingleUpdate($hash, "mute", "off", 1);
- PHILIPS_AUDIO_SendCommand($hash, "/VOLUME\$UNMUTE", "",$what, "noArg");
- }
- else
- {
- return $usage;
- }
- }
- elsif($what eq "player")
- {
- if($a[2] eq "next")
- {
- PHILIPS_AUDIO_SendCommand($hash, "/CTRL\$NEXT", "",$what, "noArg");
- }
- elsif($a[2] eq "prev")
- {
- PHILIPS_AUDIO_SendCommand($hash, "/CTRL\$PREV", "",$what, "noArg");
- }
- elsif($a[2] eq "play-pause")
- {
- PHILIPS_AUDIO_SendCommand($hash, "/CTRL\$PLAY_PAUSE", "",$what, "noArg");
- }
- elsif($a[2] eq "stop")
- {
- PHILIPS_AUDIO_SendCommand($hash, "/CTRL\$STOP", "",$what, "noArg");
- }
- else
- {
- return $usage;
- }
- }
- elsif($what =~ m/^(selectPreset|selectPresetByNumber)/)
- {
- if($a[2] ne "---")
- {
- # Hierarchichal navigation through the contents mandatory
- $hash->{helper}{cmdStep} = 1;
-
- my $presetNumber = substr($a[2], 0, 2); # Get 2 first digits
-
- if($a[2] =~ m/empty/ or ReadingsVal($name, ".inetRadioPreset_$presetNumber","") eq "empty")
- {
- # Do nothing
- }
- else
- {
- $presetNumber =~ s/^0+//g; # Remove leading '0'
- $hash->{helper}{inetRadioPreset} = $presetNumber;
- readingsSingleUpdate($hash, "input", "Internet Radio", 1);
- PHILIPS_AUDIO_SendCommand($hash, "/index", "", $what, $a[2]);
- }
- }
- }
- elsif($what =~ m/^(selectFavorite|selectFavoriteByNumber)/)
- {
- if($a[2] ne "---")
- {
- # Hierarchichal navigation through the contents mandatory
- $hash->{helper}{cmdStep} = 1;
-
- my $favoriteNumber = substr($a[2], 0, 2); # Get 2 first digits
-
- if($a[2] =~ m/empty/ or ReadingsVal($name, ".inetRadioFavorite_$favoriteNumber","") eq "empty")
- {
- # Do nothing
- }
- else
- {
- $favoriteNumber =~ s/^0+//g; # Remove leading '0'
- $hash->{helper}{inetRadioFavorite} = $favoriteNumber;
- #readingsSingleUpdate($hash, "input", "Internet Radio", 1);
- PHILIPS_AUDIO_SendCommand($hash, "/index", "", $what, $a[2]);
- }
- }
- }
- elsif($what eq "volumeStraight")
- {
- if(($a[2] < 0) || ($a[2] > 64))
- {
- return "volumeStraight must be in the range 0...64.";
- }
- else
- {
- $hash->{helper}{targetVolume} = int($a[2]);
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "volumeStraight", $hash->{helper}{targetVolume});
- readingsBulkUpdate($hash, "volume", PHILIPS_AUDIO_volume_abs2rel($hash, $hash->{helper}{targetVolume}));
- readingsEndUpdate($hash, 1);
- PHILIPS_AUDIO_SendCommand($hash, "/VOLUME\$VAL\$".$a[2], "",$what, $a[2]);
- }
- }
- elsif($what eq "volumeUp")
- {
- my $targetVolume = int(int(ReadingsVal($name, "volumeStraight", "0")) + 1);
-
- if($targetVolume > 64)
- {
- $targetVolume = 64;
- }
-
- $hash->{helper}{targetVolume} = $targetVolume;
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "volumeStraight", $hash->{helper}{targetVolume});
- readingsBulkUpdate($hash, "volume", PHILIPS_AUDIO_volume_abs2rel($hash, $hash->{helper}{targetVolume}));
- readingsEndUpdate($hash, 1);
-
- PHILIPS_AUDIO_SendCommand($hash, "/VOLUME\$VAL\$" . $hash->{helper}{targetVolume}, "",$what, $hash->{helper}{targetVolume});
- }
- elsif($what eq "volumeDown")
- {
- my $targetVolume = int(int(ReadingsVal($name, "volumeStraight", "0")) - 1);
-
- if($targetVolume < 0)
- {
- $targetVolume = 0;
- }
-
- $hash->{helper}{targetVolume} = $targetVolume;
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "volumeStraight", $hash->{helper}{targetVolume});
- readingsBulkUpdate($hash, "volume", PHILIPS_AUDIO_volume_abs2rel($hash, $hash->{helper}{targetVolume}));
- readingsEndUpdate($hash, 1);
-
- PHILIPS_AUDIO_SendCommand($hash, "/VOLUME\$VAL\$" . $hash->{helper}{targetVolume}, "",$what, $hash->{helper}{targetVolume});
- }
- elsif($what eq "volume")
- {
- if(($a[2] < 0) || ($a[2] > 100))
- {
- return "volumeStraight must be in the range 0...100.";
- }
- else
- {
- $hash->{helper}{targetVolume} = PHILIPS_AUDIO_volume_rel2abs($hash, $a[2]);
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "volumeStraight", $hash->{helper}{targetVolume});
- readingsBulkUpdate($hash, "volume", $a[2]);
- readingsEndUpdate($hash, 1);
-
- PHILIPS_AUDIO_SendCommand($hash, "/VOLUME\$VAL\$".$hash->{helper}{targetVolume}, "",$what, $hash->{helper}{targetVolume});
- }
- }
- elsif($what eq "nowplay")
- {
- PHILIPS_AUDIO_SendCommand($hash, "/nowplay", "",$what, "noArg");
- }
- elsif($what eq "homestatus")
- {
- $hash->{helper}{httpHeaderRefer} = "http://$hash->{IP_ADDRESS}:$hash->{PORT}/index\r\n";
- PHILIPS_AUDIO_SendCommand($hash, "/HOMESTATUS", "",$what, "noArg");
- }
- elsif($what eq "getPresets")
- {
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "playerListStatus", "busy");
- readingsBulkUpdate($hash, "readingPresets", "yes");
- readingsEndUpdate($hash, 1);
-
- # Delete old redings
- delete $hash->{READINGS}{$_} foreach (grep /.inetRadioPreset_..$/, keys %{$hash->{READINGS}});
-
- # Hierarchichal navigation through the contents mandatory
- $hash->{helper}{cmdStep} = 1;
- PHILIPS_AUDIO_SendCommand($hash, "/index", "", $what, "noArg");
- }
- elsif($what eq "getFavorites")
- {
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "playerListStatus", "busy");
- readingsBulkUpdate($hash, "readingFavorites", "yes");
- readingsEndUpdate($hash, 1);
-
- # Delete old redings
- delete $hash->{READINGS}{$_} foreach (grep /.inetRadioFavorite_..$/, keys %{$hash->{READINGS}});
-
- # Hierarchichal navigation through the contents mandatory
- $hash->{helper}{cmdStep} = 1;
- PHILIPS_AUDIO_SendCommand($hash, "/index", "", $what, "noArg");
- }
- elsif($what eq "selectStream")
- {
-
- # The player list selection has been designed for a GUI/touchscreen
- # Virtually scrolling down to last item and choosing the first one
- # arises an error. Needs to navigate back to the corresponding page
- # consisting of 8 items per page
-
- readingsSingleUpdate($hash, "playerListStatus", "busy", 1);
-
- if($a[2] =~ /lvl_(.+?)/)
- {
- my $desiredLevel = $1;
- my $currentUrl = $hash->{helper}{currentNavUrl};
- my $newUrl = "";
- my $currentLevel = "";
- my $newLevel = "";
-
- if($currentUrl =~ /\/nav\$(.*)\$(.*)\$(.*)\$(.*)/) # e.g. /nav$02$XX$001$0
- {
- $currentLevel = int($2);
- $newLevel = sprintf("%02d", $currentLevel - ($currentLevel - $desiredLevel) + 1);
- $newUrl = "/nav\$$1\$$newLevel\$$3\$0";
- }
-
- PHILIPS_AUDIO_SendCommand($hash, $newUrl, "", $what, $a[2]);
- }
- elsif($a[2] ne "---")
- {
- my $targetNr = substr($a[2], 0, 3);
- my $currentUrl = $hash->{helper}{currentNavUrl};
-
- # Remark TODO...
-
- if($a[2] =~ /(\d{3})_(.+?)_(.*)/)
- {
- my $currentListLevel = ReadingsVal($name, ".listDepthLevel", "");
- readingsSingleUpdate($hash, ".lvl_".$currentListLevel."_name", "$2_$3", 1);
-
- if(int(ReadingsVal($name, "playerListTotalCount", "8")) > 8)
- {
- if($currentUrl =~ /\/nav\$(.*)\$(.*)\$(.*)\$(.*)/)
- {
- # Virtually scroll back to the first line
-
- my $scrollUrl = "\/nav\$$1\$$2\$001\$$4";
-
- PHILIPS_AUDIO_SendCommand($hash, $scrollUrl, "", "selectStream", "scroll");
-
- # int(($targetNr / 8) + 0.5) -> Round up
- for(my $i = 1; $i < (int(($targetNr / 8) + 0.5) + 1); $i += 8) # Max 8 items in the actual list
- {
- my $scrollUrl = "\/nav\$$1\$$2\$".sprintf("%003s", ($i + 8))."\$$4";
-
- PHILIPS_AUDIO_SendCommand($hash, $scrollUrl, "", "selectStream", "scroll");
- }
- }
- }
- }
- PHILIPS_AUDIO_SendCommand($hash, ReadingsVal($name, ".listItemTarget_$targetNr", ""), "", $what, $a[2]);
- }
- else
- {
- return $usage;
- }
- }
- else
- {
- return $usage;
- }
- PHILIPS_AUDIO_ResetTimer($hash); # Reset timer for the next loop
-
- return;
- }
- sub PHILIPS_AUDIO_Define
- {
- my ($hash, $def) = @_;
- my @a = split("[ \t][ \t]*", $def);
- my $name = $hash->{NAME};
-
- # Implemented devices for reading Device Description
- @{$hash->{helper}{DevDescImplementedModels}} = qw( AW9000 NP3500 NP3700 NP3900 );
-
- $hash->{helper}{sendCommandBuffer} = [];
-
- delete $hash->{READINGS}{$_} foreach (grep /player/, keys %{$hash->{READINGS}});
-
- if(! @a >= 4)
- {
- my $msg = "Wrong syntax: define <name> PHILIPS_AUDIO <model> <ip-or-hostname> [<ON-statusinterval>] [<OFF-statusinterval>] ";
- Log3 $name, 2, $msg;
- return $msg;
- }
-
- if(defined($a[2]))
- {
- $hash->{MODEL} = uc($a[2]);
-
- # Used by 'fheminfo' command for statistics
- $attr{$name}{"model"} = $hash->{MODEL};
- }
-
- $hash->{IP_ADDRESS} = $a[3];
- $hash->{PORT} = 8889;
-
- # if an update interval >= 5 use it.
- if(defined($a[4]) and $a[4] > 0)
- {
- $hash->{helper}{OFF_INTERVAL} = $a[4];
- # Minimum interval 5 sec
- if($hash->{helper}{OFF_INTERVAL} < 5)
- {
- $hash->{helper}{OFF_INTERVAL} = 5;
- }
- }
- else
- {
- $hash->{helper}{OFF_INTERVAL} = 30;
- }
-
- if(defined($a[5]) and $a[5] > 0)
- {
- $hash->{helper}{ON_INTERVAL} = $a[5];
- # Minimum interval 5 sec
- if($hash->{helper}{ON_INTERVAL} < 5)
- {
- $hash->{helper}{ON_INTERVAL} = 5;
- }
- }
- else
- {
- $hash->{helper}{ON_INTERVAL} = $hash->{helper}{OFF_INTERVAL};
- }
-
- unless(exists($hash->{helper}{AVAILABLE}) and ($hash->{helper}{AVAILABLE} == 0))
- {
- $hash->{helper}{AVAILABLE} = 1;
- readingsSingleUpdate($hash, "presence", "present", 1);
- }
-
- # start the status update timer
- $hash->{helper}{DISABLED} = 0 unless(exists($hash->{helper}{DISABLED}));
-
- PHILIPS_AUDIO_ResetTimer($hash, 0);
-
- return;
- }
- sub PHILIPS_AUDIO_Attr
- {
- my ($cmd, $name, $attrName, $attrVal) = @_;
- my $hash = $defs{$name};
-
- if($attrName eq "disable")
- {
- if ($cmd eq "set")
- {
- $hash->{helper}{DISABLED} = $attrVal;
- if ($attrVal eq "0")
- {
- PHILIPS_AUDIO_GetStatus($hash, 1);
- }
- }
- else
- {
- $hash->{helper}{DISABLED} = 0;
- PHILIPS_AUDIO_GetStatus($hash, 1);
- }
- }
- elsif($attrName eq "maxListItems" && defined($attrVal))
- {
- if ($cmd eq "set" && (($attrVal < 8) || ($attrVal > 999)))
- {
- return "$attrName must be between 8 and 999";
- }
- }
- elsif($attrName eq "httpBufferTimeout" && defined($attrVal))
- {
- if ($cmd eq "set" && (($attrVal < 10) || ($attrVal > 15)))
- {
- return "$attrName must be between 10 and 15";
- }
- }
- elsif($attrName eq "requestTimeout" && defined($attrVal))
- {
- if ($cmd eq "set" && (($attrVal < 10) || ($attrVal > 15)))
- {
- return "$attrName must be between 10 and 15";
- }
- }
- elsif($attrName eq "autoGetPresets" && defined($attrVal))
- {
- if ($cmd eq "set" && (($attrVal < 0) || ($attrVal > 1)))
- {
- return "$attrName must be between 0 or 1";
- }
- }
- elsif($attrName eq "autoGetFavorites" && defined($attrVal))
- {
- if ($cmd eq "set" && (($attrVal < 0) || ($attrVal > 1)))
- {
- return "$attrName must be between 0 or 1";
- }
- }
- elsif($attrName eq "playerBrowsingTimeout" && defined($attrVal))
- {
- if ($cmd eq "set" && (($attrVal < 60) || ($attrVal > 600)))
- {
- return "$attrName must be between 60 or 600";
- }
- }
-
- # Start/Stop Timer according to new disabled-Value
- PHILIPS_AUDIO_ResetTimer($hash);
- return;
- }
- sub PHILIPS_AUDIO_Undefine
- {
- my($hash, $name) = @_;
- # Stop the internal GetStatus-Loop and exit
- RemoveInternalTimer($hash, "PHILIPS_AUDIO_GetStatus");
- return;
- }
- sub PHILIPS_AUDIO_SendCommandBuffer
- {
- # Function called by an internal timer in case device busy
- my ($hash) = @_;
-
- my $firstCommand = "";
- my ($url, $data, $cmd, $arg) = ("", "", "", "");
-
-
- # Get first command from buffer
- if
- (
- @{$hash->{helper}{sendCommandBuffer}}
- )
- {
- $firstCommand = shift(@{$hash->{helper}{sendCommandBuffer}});
-
- $url = $firstCommand->{url};
- $data = $firstCommand->{data};
- $cmd = $firstCommand->{cmd};
- $arg = $firstCommand->{arg};
- }
-
- # Only send in case buffer not empty
- if(($url ne "") and ($cmd ne "") and ($arg ne "")) # $data may be empty
- {
-
- $hash->{helper}{comeFromSendBuffer} = 1;
-
- PHILIPS_AUDIO_SendCommand(
- $hash,
- $url,
- $data,
- $cmd,
- $arg
- );
-
-
- # Check if buffer empty
- if
- (
- (@{$hash->{helper}{sendCommandBuffer}})
- )
- {
- # Come back
- # -> try again after 1 sec delay and process buffer.
- RemoveInternalTimer($hash, "PHILIPS_AUDIO_SendCommandBuffer");
- InternalTimer(gettimeofday() + 1, "PHILIPS_AUDIO_SendCommandBuffer", $hash);
- }
-
- }
- else
- {
- # Do nothing.
- # Reset flag in case buffer empty
- $hash->{helper}{comeFromSendBuffer} = 0;
- PHILIPS_AUDIO_ResetTimer($hash);
- }
-
- return;
- }
- sub PHILIPS_AUDIO_SendCommand
- {
- my ($hash, $url, $data, $cmd, $arg) = @_;
- my $name = $hash->{NAME};
- my $address = $hash->{IP_ADDRESS};
- my $port = $hash->{PORT};
-
- $hash->{helper}{networkRequest} = "idle" if(not defined($hash->{helper}{networkRequest})); # First run
- $hash->{helper}{comeFromSendBuffer} = 0 if(not defined($hash->{helper}{comeFromSendBuffer})); # First run
-
- # buffer command and wait a second in case device busy
- if ($hash->{helper}{networkRequest} eq "busy")
- {
-
- my $httpBufferData =
- {
- url => $url,
- data => $data,
- cmd => $cmd,
- arg => $arg
- };
-
- # Append to buffer only if not coming from itself
- # Or put to first position for resending
-
- # add remove start end
- # push X X
- # pop X X
- # unshift X X
- # shift X X
-
- if($hash->{helper}{comeFromSendBuffer} == 0)
- {
- push @{$hash->{helper}{sendCommandBuffer}}, $httpBufferData;
- }
- else
- {
- unshift @{$hash->{helper}{sendCommandBuffer}}, $httpBufferData;
- }
-
- if($hash->{helper}{timeoutCounter} >= AttrVal($name, "httpBufferTimeout", 10))
- {
- # X seconds timeout. Something went wrong. Clear buffer. Release "busy"
-
- # Delete all remaining commands
- splice(@{$hash->{helper}{sendCommandBuffer}});
-
- $hash->{helper}{timeoutCounter} = 0;
- $hash->{helper}{networkRequest} = "idle";
- $hash->{helper}{comeFromSendBuffer} = 0;
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate ($hash, "networkRequest", "idle");
- readingsBulkUpdate ($hash, "networkError", "buffer timed out");
- readingsEndUpdate ($hash, 1);
-
- Log3 $name, 3, "PHILIPS_AUDIO ($name) - HTTP buffer timeout. Please, check your network connection, ip-address etc. Device switched off?";
-
- PHILIPS_AUDIO_ResetTimer($hash);
-
- return;
- }
-
- # -> try again after 1 sec delay and process buffer.
- RemoveInternalTimer($hash, "PHILIPS_AUDIO_SendCommandBuffer");
- InternalTimer(gettimeofday() + 1, "PHILIPS_AUDIO_SendCommandBuffer", $hash);
-
- return;
- }
- else
- {
- if($url =~ /\/nav(.*)/)
- {
- $hash->{helper}{currentNavUrl} = $url;
- }
- else
- {
- $hash->{helper}{currentUrl} = $url;
- }
-
- if(ReadingsVal($name, "presence", "absent") ne "absent")
- {
- $hash->{helper}{networkRequest} = "busy";
- readingsSingleUpdate($hash, "networkRequest", "busy", 1);
- }
-
- PHILIPS_AUDIO_ResetTimer($hash); # getStatus
- }
-
- $hash->{helper}{timeoutCounter} = 0;
-
- Log3 $name, 5, "PHILIPS_AUDIO ($name) - Executing nonblocking \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\" on $name: $data";
-
- # Reset flag if successfully sent
- $hash->{helper}{comeFromSendBuffer} = 0;
-
- HttpUtils_NonblockingGet
- ({
- url => "http://".$address.":".$port."".$url,
- timeout => AttrVal($name, "requestTimeout", 10),
- noshutdown => 1,
- data => $data,
- loglevel => ($hash->{helper}{AVAILABLE} ? undef : 5),
- hash => $hash,
- cmd => $cmd,
- arg => $arg,
- method => "GET",
- httpversion => "1.1",
- keepalive => 1, # Philips app always uses keep-alive
- header => $hash->{helper}{httpHeaderRefer},
- callback => \&PHILIPS_AUDIO_ParseResponse
- });
-
- return;
- }
- sub PHILIPS_AUDIO_ParseResponse
- {
- my ($param, $err, $data ) = @_;
-
- my $hash = $param->{hash};
- my $name = $hash ->{NAME};
- my $cmd = $param->{cmd};
- my $arg = $param->{arg};
-
- if(exists($param->{code}))
- {
- Log3 $name, 5, "PHILIPS_AUDIO ($name) - received HTTP code ".$param->{code}." for command \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\"";
- }
-
- if($err ne "")
- {
- readingsBeginUpdate($hash);
-
- Log3 $name, 5, "PHILIPS_AUDIO ($name) - Could not execute command \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\": $err";
-
- # Release the busy flag
- $hash->{helper}{networkRequest} = "idle";
- readingsBulkUpdate($hash, "networkRequest", "idle");
-
- if((not exists($hash->{helper}{AVAILABLE})) or (exists($hash->{helper}{AVAILABLE}) and $hash->{helper}{AVAILABLE} == 1))
- {
- Log3 $name, 3, "PHILIPS_AUDIO ($name) - Could not execute HTTP request. Please, check your network connection, ip-address etc. Device switched off? ($err)";
- readingsBulkUpdate($hash, "networkError", "$err");
- readingsBulkUpdate($hash, "presence", "absent");
- readingsBulkUpdate($hash, "state", "absent");
- $hash->{STATE} = "absent";
- }
-
- $hash->{helper}{AVAILABLE} = 0;
- $hash->{helper}{timeoutCounter} = 0;
- $hash->{helper}{comeFromSendBuffer} = 0;
-
- # Close HTTP connection
- HttpUtils_Close($param);
-
- # Force "home" state
- $hash->{helper}{playerState} = "home";
- readingsBulkUpdate($hash, "playerState", "home");
- readingsBulkUpdate($hash, "playerListStatus", "ready");
-
- readingsEndUpdate($hash, 1);
-
- # Device firware "somehow buggy".
- # Try to reanimate the device after timeout.
- # Go to /index
- PHILIPS_AUDIO_SendCommand($hash, "/index", "","home", "noArg");
-
- PHILIPS_AUDIO_ResetTimer($hash);
- return;
- }
- elsif($data ne "")
- {
-
- Log3 $name, 5, "PHILIPS_AUDIO ($name) - got response for \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\": $data";
-
- delete $hash->{READINGS}{networkError};
-
- readingsBeginUpdate($hash);
-
- if (defined($hash->{helper}{AVAILABLE}) and $hash->{helper}{AVAILABLE} eq 0)
- {
- Log3 $name, 3, "PHILIPS_AUDIO ($name) - device $name reappeared";
- readingsBulkUpdate($hash, "presence", "present");
- }
-
- $hash->{helper}{AVAILABLE} = 1;
-
- readingsBulkUpdate($hash, "power", "on");
- readingsBulkUpdate($hash, "state","on");
-
- $hash->{STATE} = "on";
-
- readingsEndUpdate($hash, 1);
-
- if($cmd eq "standbyButton")
- {
- if($data =~ /SUCCESS/)
- {
- #readingsBulkUpdate($hash, "power", "on");
- #readingsBulkUpdate($hash, "state","on");
- }
-
- }
- elsif($cmd eq "home")
- {
- if($data =~ /'devicename'/) # Device responded correctly
- {
- $hash->{helper}{playerState} = "home";
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate ($hash, "playerState", "home");
- readingsBulkUpdate ($hash, "playerListStatus", "ready");
- readingsEndUpdate ($hash, 1);
- }
- }
- elsif($cmd eq "mute")
- {
- if($data =~ /SUCCESS/)
- {
- readingsSingleUpdate($hash, "mute", "on", 1);
- }
- }
- elsif($cmd eq "unmute")
- {
- if($data =~ /SUCCESS/)
- {
- readingsSingleUpdate($hash, "mute", "off", 1);
- }
- }
- elsif($cmd eq "favoriteRemove")
- {
- # replace \n by ""
- $data =~ s/\n//g;
-
- if($data =~ /{'command':'MESSAGE','value':'(.+)'}/)
- {
- # Do nothing
- }
- }
- elsif($cmd eq "favoriteAdd")
- {
- # replace \n by ""
- $data =~ s/\n//g;
-
- if($data =~ /{'command':'MESSAGE','value':'(.+)'}/)
- {
- # Do nothing
- }
- }
- elsif($cmd =~ m/^(selectPreset|inetRadioPreset)/)
- {
- # This command must be processed hierarchicaly through the navigation path
- if($hash->{helper}{cmdStep} == 1)
- {
- $hash->{helper}{cmdStep} = 2;
-
- # External Command. Not from buffer timer.
- $hash->{helper}{fromSendCommandBuffer} = 0;
- # Internet radio
- PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$01\$001\$0", "", "selectPreset", $hash->{helper}{inetRadioPreset});
- }
- elsif($hash->{helper}{cmdStep} == 2)
- {
- $hash->{helper}{cmdStep} = 3;
-
- # External Command. Not from buffer timer.
- $hash->{helper}{fromSendCommandBuffer} = 0;
- # Presets
- PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$02\$001\$0", "","selectPreset", $hash->{helper}{inetRadioPreset});
- }
- elsif($hash->{helper}{cmdStep} == 3)
- {
- $hash->{helper}{cmdStep} = 4;
-
- # External Command. Not from buffer timer.
- $hash->{helper}{fromSendCommandBuffer} = 0;
-
- # Preset select
- PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$03\$".sprintf("%03d", $hash->{helper}{inetRadioPreset})."\$1", "","selectPreset", $hash->{helper}{inetRadioPreset});
-
- $hash->{helper}{playerState} = "playing";
- readingsSingleUpdate($hash, "playerState", "playing", 1);
- }
-
- }
- elsif($cmd =~ m/^(selectFavorite|inetRadioFavorite)/)
- {
- # This command must be processed hierarchicaly through the navigation path
- if($hash->{helper}{cmdStep} == 1)
- {
- $hash->{helper}{cmdStep} = 2;
- # Internet radio favorite# External Command. Not from buffer timer.
- $hash->{helper}{fromSendCommandBuffer} = 0;
- PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$01\$001\$0", "", "selectFavorite", $hash->{helper}{inetRadioFavorite});
- }
- elsif($hash->{helper}{cmdStep} == 2)
- {
- $hash->{helper}{cmdStep} = 3;
-
- # External Command. Not from buffer timer.
- $hash->{helper}{fromSendCommandBuffer} = 0;
-
- # Favorite Presets
- PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$02\$002\$0", "","selectFavorite", $hash->{helper}{inetRadioFavorite});
- }
- elsif($hash->{helper}{cmdStep} == 3)
- {
- $hash->{helper}{cmdStep} = 4;
-
- # External Command. Not from buffer timer.
- $hash->{helper}{fromSendCommandBuffer} = 0;
-
- # Favorite Preset select
- PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$03\$".sprintf("%03d", $hash->{helper}{inetRadioFavorite})."\$1", "","selectFavorite", $hash->{helper}{inetRadioFavorite});
-
- $hash->{helper}{playerState} = "playing";
- readingsSingleUpdate($hash, "playerState", "playing", 1);
- }
- }
- elsif($cmd eq "play_pause")
- {
- if($data =~ /SUCCESS/)
- {
- if(ReadingsVal($name, "playerPlaying", "") eq "no")
- {
- readingsSingleUpdate($hash, "playerPlaying", "yes", 1);
- }
- else
- {
- delete $hash->{READINGS}{$_} foreach (grep /player/, keys %{$hash->{READINGS}});
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "playerPlaying", "no");
- readingsBulkUpdate($hash, "input", "-");
- readingsEndUpdate($hash, 1);
- }
- }
- }
- elsif($cmd eq "stop")
- {
- if($data =~ /STOP/)
- {
- delete $hash->{READINGS}{$_} foreach (grep /player/, keys %{$hash->{READINGS}});
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "playerPlaying", "no");
- readingsBulkUpdate($hash, "input", "-");
- readingsEndUpdate($hash, 1);
- }
- }
- elsif($cmd =~ m/^(volumeStraight|volumeUp|volumeDown)/)
- {
- if($data =~ /SUCCESS/)
- {
- my $targetVolume = $hash->{helper}{targetVolume};
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "volumeStraight", $hash->{helper}{targetVolume});
- readingsBulkUpdate($hash, "volume", PHILIPS_AUDIO_volume_abs2rel($hash, $targetVolume));
- readingsEndUpdate($hash, 1);
- }
- }
- elsif($cmd eq "elapse")
- {
- if($data =~ /'command':'(.+)',/)
- {
- if($1 eq "NOWPLAY")
- {
- # New player status information available
- readingsSingleUpdate($hash, "playerPlaying", "yes", 1);
- PHILIPS_AUDIO_SendCommand($hash, "/nowplay", "","nowplay", "noArg");
- }
- elsif($1 eq "ELAPSE")
- {
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "playerPlaying", "yes");
-
- if($data =~ /'value':(.+),/)
- {
- # Sometimes the device does not refresh the ELAPSE -> NOWPLAY request
- # Showing the current stream position.
- # Check for a new song.
-
- $hash->{helper}{elapseValueOld} = "0" if(not defined($hash->{helper}{elapseValueOld}));
-
- if (int($1) < int($hash->{helper}{elapseValueOld})) # New song
- {
- PHILIPS_AUDIO_SendCommand($hash, "/nowplay", "","nowplay", "noArg");
- }
-
- $hash->{helper}{elapseValueOld} = $1;
-
- if(int($1) < 3600)
- {
- readingsBulkUpdate($hash, "playerPlayTime", strftime("%M:\%S", gmtime($1)));
- }
- else
- {
- readingsBulkUpdate($hash, "playerPlayTime", strftime("\%H:\%M:\%S", gmtime($1)));
- }
- }
- if($data =~ /'mute':(.+),/)
- {
- if(int($1) == 1)
- {
- readingsBulkUpdate($hash, "mute", "on");
- }
- else
- {
- readingsBulkUpdate($hash, "mute", "off");
- }
- }
- if($data =~ /'shuffle':(.+),/)
- {
- if(int($1) == 1)
- {
- readingsBulkUpdate($hash, "playerShuffle", "on");
- }
- else
- {
- readingsBulkUpdate($hash, "playerShuffle", "off");
- }
- }
- if($data =~ /'repeat':(.+),/)
- {
- if(int($1) == 0)
- {
- readingsBulkUpdate($hash, "playerRepeat", "off");
- }
- elsif(int($1) == 1)
- {
- readingsBulkUpdate($hash, "playerRepeat", "single");
- }
- elsif(int($1) == 2)
- {
- readingsBulkUpdate($hash, "playerRepeat", "all");
- }
- }
- if($data =~ /'rating':(.+),/)
- {
- readingsBulkUpdate($hash, "playerStreamRating", $1);
- }
- if($data =~ /'favstatus':(.+)}/)
- {
- if(int($1) == 1)
- {
- readingsBulkUpdate($hash, "playerStreamFavorite", "yes");
- }
- else
- {
- readingsBulkUpdate($hash, "playerStreamFavorite", "no");
- }
- }
- if($data =~ /'volume':(.+),/)
- {
- readingsBulkUpdate($hash, "volumeStraight", $1);
- readingsBulkUpdate($hash, "volume", PHILIPS_AUDIO_volume_abs2rel($hash, $1));
- }
-
- readingsEndUpdate($hash, 1);
-
- if($data =~ /'play':(.+),/)
- {
- if(int($1) == 1)
- {
- $hash->{helper}{playerState} = "playing";
- readingsBeginUpdate($hash);
- readingsBulkUpdate ($hash, "playerPlaying", "yes");
- readingsBulkUpdate ($hash, "playerState", "playing");
- readingsEndUpdate ($hash, 1);
- }
- else
- {
- delete $hash->{READINGS}{$_} foreach (grep /player/, keys %{$hash->{READINGS}});
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate ($hash, "playerPlaying", "no");
- readingsBulkUpdate ($hash, "playerState", "home");
- readingsEndUpdate ($hash, 1);
- }
- }
- }
- }
- }
- elsif($cmd eq "nowplay")
- {
- if($data =~ /'command':'(.+)',/)
- {
- if($1 eq "NOTHING")
- {
- delete $hash->{READINGS}{$_} foreach (grep /player/, keys %{$hash->{READINGS}});
-
- $hash->{helper}{playerState} = "home";
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate ($hash, "playerPlaying", "no");
- readingsBulkUpdate ($hash, "playerState", "home");
- readingsEndUpdate ($hash, 1);
- }
- }
- elsif($data =~ /window.location = \"\/index\"/)
- {
- delete $hash->{READINGS}{$_} foreach (grep /player/, keys %{$hash->{READINGS}});
-
- $hash->{helper}{playerState} = "home";
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate ($hash, "playerPlaying", "no");
- readingsBulkUpdate ($hash, "playerState", "home");
- readingsEndUpdate ($hash, 1);
- }
- else
- {
- $hash->{helper}{playerState} = "playing";
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate ($hash, "playerPlaying", "yes");
- readingsBulkUpdate ($hash, "playerState", "playing");
- readingsEndUpdate ($hash, 1);
- }
-
- if($data =~ /'devicename':'(.*?)'/)
- {
- if(not defined ($hash->{FRIENDLY_NAME}))
- {
- $hash->{FRIENDLY_NAME} = $1;
- $hash->{helper}{dInfo}{FRIENDLY_NAME} = $1;
- }
- }
-
- readingsBeginUpdate($hash);
-
- if ($data =~ /'defaultAlbumArt':'res\/Internet_radio.jpg'/)
- {
- readingsBulkUpdate($hash, "input", "Internet Radio");
- }
-
- if($data =~ /'defaultAlbumArt':'res\/Media_library.jpg'/)
- {
- readingsBulkUpdate($hash, "input", "Media Library");
- }
-
- if($data =~ /'defaultAlbumArt':'res\/Home_AUX_nowplaying.jpg'/)
- {
- if($hash->{MODEL} eq "AW9000")
- {
- if($data =~ />Aux-in</)
- {
- readingsBulkUpdate($hash, "input", "Aux-in (analog)");
- }
- elsif($data =~ />Digital-in 1(.+)</)
- {
- readingsBulkUpdate($hash, "input", "Digital-in 1 (coaxial)");
- }
- elsif($data =~ />Digital-in 2(.+)</)
- {
- readingsBulkUpdate($hash, "input", "Digital-in 2 (optical)");
- }
- elsif($data =~ />MP3-Link</)
- {
- readingsBulkUpdate($hash, "input", "MP3-Link");
- }
- }
- else
- {
- readingsBulkUpdate($hash, "input", "MP3-Link");
- }
- }
-
- if($data =~ /'defaultAlbumArt':'res\/spot_Nowplaying_AA.png'/)
- {
- readingsBulkUpdate($hash, "input", "Spotify");
- }
-
- if($data =~ /'defaultAlbumArt':'res\/Home_OnlineServices.png'/)
- {
- readingsBulkUpdate($hash, "input", "Online Services");
- }
-
- readingsEndUpdate($hash, 1);
-
- if($data =~ /'title':'\\'(.+)\\''/)
- {
- if((ReadingsVal($name, "input", "") eq "Media Library") or (ReadingsVal($name, "input", "") eq "Spotify"))
- {
- readingsSingleUpdate($hash, "playerTitle", PHILIPS_AUDIO_html2txt($1), 1);
- delete $hash->{READINGS}{playerRadioStationInfo};
- }
- elsif(ReadingsVal($name, "input", "") eq "Internet Radio")
- {
- readingsSingleUpdate($hash, "playerRadioStationInfo", PHILIPS_AUDIO_html2txt($1), 1);
- delete $hash->{READINGS}{playerTitle};
- }
- }
- elsif($data =~ /'title':'(.+)'/)
- {
- if((ReadingsVal($name, "input", "") eq "Media Library") or (ReadingsVal($name, "input", "") eq "Spotify"))
- {
- readingsSingleUpdate($hash, "playerTitle", PHILIPS_AUDIO_html2txt($1), 1);
- delete $hash->{READINGS}{playerRadioStationInfo};
- }
- elsif(ReadingsVal($name, "input", "") eq "Internet Radio")
- {
- readingsSingleUpdate($hash, "playerRadioStationInfo", PHILIPS_AUDIO_html2txt($1), 1);
- delete $hash->{READINGS}{playerTitle};
- }
- }
- else
- {
- delete $hash->{READINGS}{playerTitle};
- delete $hash->{READINGS}{playerRadioStationInfo};
- }
-
- if($data =~ /'subTitle':'(.+)'/)
- {
- if((ReadingsVal($name, "input", "") eq "Media Library") or (ReadingsVal($name, "input", "") eq "Spotify"))
- {
- readingsSingleUpdate($hash, "playerAlbum", PHILIPS_AUDIO_html2txt($1), 1);
- delete $hash->{READINGS}{playerRadioStation};
- }
- else
- {
- readingsSingleUpdate($hash, "playerRadioStation", PHILIPS_AUDIO_html2txt($1), 1);
- delete $hash->{READINGS}{playerAlbum};
- }
- }
- else
- {
- delete $hash->{READINGS}{playerRadioStation};
- delete $hash->{READINGS}{playerAlbum};
- }
-
- if($data =~ /'albumArt':'(.+)'/)
- {
- readingsSingleUpdate($hash, "playerAlbumArt", $1, 1);
- }
- else
- {
- delete $hash->{READINGS}{playerAlbumArt};
- }
-
- readingsBeginUpdate($hash);
-
- if($data =~ /'volume':(.+),/)
- {
- readingsBulkUpdate($hash, "volumeStraight", $1);
- readingsBulkUpdate($hash, "volume", PHILIPS_AUDIO_volume_abs2rel($hash, $1));
- }
- else
- {
- readingsBulkUpdate($hash, "volumeStraight", "0");
- readingsBulkUpdate($hash, "volume", "0");
- }
-
- readingsEndUpdate($hash, 1);
-
- if($data =~ /'elapsetime':(.+),/)
- {
- if(int($1) < 3600)
- {
- readingsSingleUpdate($hash, "playerPlayTime", strftime("%M:\%S", gmtime($1)), 1);
- }
- else
- {
- readingsSingleUpdate($hash, "playerPlayTime", strftime("\%H:\%M:\%S", gmtime($1)), 1);
- }
- }
- else
- {
- delete $hash->{READINGS}{playerPlayTime};
- }
-
- if($data =~ /'totaltime':(.+),/)
- {
- # Playing radio delivers that total time
- if($1 eq "65535")
- {
- delete $hash->{READINGS}{playerTotalPlayTime};
- }
- elsif(int($1) < 3600)
- {
- readingsSingleUpdate($hash, "playerTotalPlayTime", strftime("%M:\%S", gmtime($1)), 1);
- }
- else
- {
- readingsSingleUpdate($hash, "playerTotalPlayTime", strftime("\%H:\%M:\%S", gmtime($1)), 1);
- }
- }
- else
- {
- delete $hash->{READINGS}{playerTotalPlayTime};
- }
-
- if($data =~ /'muteStatus':(.+),/)
- {
- if($1 == 1)
- {
- readingsSingleUpdate($hash, "mute", "on", 1);
- }
- else
- {
- readingsSingleUpdate($hash, "mute", "off", 1);
- }
- }
-
- # typo in the (buggy) Streamium firmware...
- if($data =~ /'playStaus':(.+),/)
- {
- if($1 == 1)
- {
- readingsSingleUpdate($hash, "playerPlaying", "yes", 1);
- }
- else
- {
- delete $hash->{READINGS}{$_} foreach (grep /player/, keys %{$hash->{READINGS}});
- readingsSingleUpdate($hash, "playerPlaying", "no", 1);
- }
- }
- else
- {
- delete $hash->{READINGS}{$_} foreach (grep /player/, keys %{$hash->{READINGS}});
- readingsSingleUpdate($hash, "playerPlaying", "no", 1);
- }
- }
- elsif($cmd eq "homestatus")
- {
- # Homestatus answers with
- # {'command':'NOTHING',\n'value':0}
-
- # Do nothing ?
- }
- elsif ($cmd eq "getMediaRendererDesc")
- {
- if($data =~ /<manufacturer>(.+)<\/manufacturer>/)
- {
- $hash->{helper}{dInfo}{MANUFACTURER} = $1;
- }
-
- if($data =~ /<manufacturerURL>(.+)<\/manufacturerURL>/)
- {
- $hash->{helper}{dInfo}{MANUFACTURER_URL} = $1;
- }
-
- if($data =~ /<manufacturerURL>(.+)<\/manufacturerURL>/)
- {
- $hash->{helper}{dInfo}{MANUFACTURER_URL} = $1;
- }
-
- if($data =~ /<presentationURL>(.+)<\/presentationURL>/)
- {
- $hash->{helper}{dInfo}{PRESENTATION_URL} = $1;
- }
-
- if($data =~ /<deviceType>(.+)<\/deviceType>/)
- {
- $hash->{helper}{dInfo}{UPNP_DEVICE_TYPE} = $1;
- }
-
- if($data =~ /<friendlyName>(.+)<\/friendlyName>/)
- {
- $hash->{helper}{dInfo}{FRIENDLY_NAME} = $1;
- }
- if($data =~ /<UDN>(.+)<\/UDN>/)
- {
- my $uuid = uc($1);
- $uuid =~ s/UUID://g;
- $hash->{helper}{dInfo}{UUID} = $uuid;
- }
-
- if($data =~ /<UPC>(.+)<\/UPC>/)
- {
- $hash->{helper}{dInfo}{UPC} = $1;
- }
-
- if($data =~ /<modelName>(.+)<\/modelName>/)
- {
- $hash->{helper}{dInfo}{MODEL_NAME} = $1;
- }
- if($data =~ /<modelNumber>(.+)<\/modelNumber>/)
- {
- $hash->{helper}{dInfo}{MODEL_NUMBER} = $1;
- }
-
- if($data =~ /<serialNumber>(.+)<\/serialNumber>/)
- {
- $hash->{helper}{dInfo}{SERIAL_NUMBER} = uc($1);
- }
- if($data =~ /<modelDescription>(.+)<\/modelDescription>/)
- {
- $hash->{helper}{dInfo}{MODEL_DESCRIPTION} = $1;
- }
- # Replace \n, \r, \t from the string for XML parsing
-
- # replace \n by ""
- $data =~ s/\n//g;
-
- # replace \t by ""
- $data =~ s/\t//g;
-
- # replace \r by ""
- $data =~ s/\r//g;
-
- if($data =~ /<iconList>(.+?)<\/iconList>/)
- {
- my $address = $hash->{IP_ADDRESS};
- my $port = "";
-
- if (uc($hash->{MODEL}) eq "NP3700")
- {
- $port = 7123;
- }
- elsif
- (
- (uc($hash->{MODEL}) eq "NP3500") or
- (uc($hash->{MODEL}) eq "NP3900") or
- (uc($hash->{MODEL}) eq "AW9000")
- )
- {
- $port = 49153;
- }
-
- my $i = 1;
-
- while ($data =~ /<url>(.+?)<\/url>/g)
- {
- # May have several urls according to the UPNP/DLNA standard
- $hash->{helper}{dInfo}{"DEVICE_ICON_$i"} = "http://$address:$port/$1";
- $i++;
- }
- }
- }
- elsif ($cmd eq "getPresets")
- {
- $hash->{helper}{TOTALINETRADIOPRESETS} = 0 if(not defined($hash->{helper}{TOTALINETRADIOPRESETS}));
-
- # This command must be processed hierarchicaly through the navigation path
- if($hash->{helper}{cmdStep} == 1)
- {
- $hash->{helper}{cmdStep} = 2;
- # Internet radio
- PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$01\$001\$0", "","getPresets", "noArg");
- }
- elsif($hash->{helper}{cmdStep} == 2)
- {
- $hash->{helper}{cmdStep} = 3;
- # Presets
- PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$02\$001\$0", "","getPresets", "noArg");
- }
- elsif($hash->{helper}{cmdStep} == 3)
- {
- my $listedItems; # Visible Items in the display. Max 8
- my $nextreqURL;
- my $i;
- my $presetID = 0;
- my $presetName;
- # Parse first 8 Presets
- if($data =~ /<title>Error<\/title>/)
- {
- # In case on presets defined the player returns an Error
- # Do nothing
- $hash->{helper}{TOTALINETRADIOPRESETS} = 0;
- readingsSingleUpdate($hash, "totalPresets", "0", 1);
- delete $hash->{READINGS}{Reading_presets};
- }
- else
- {
- if ($data =~ /'nextrequrl':'(.+?)',/)
- {
- $nextreqURL = $1;
- #Log3 $name, 5, "NextreqURL: $nextreqURL";
- }
- if ($data =~ /'totalListCount':(.+),/)
- {
- $hash->{helper}{TOTALINETRADIOPRESETS} = $1;
- readingsSingleUpdate($hash, "totalPresets", $1, 1);
- #Log3 $name, 5, "ListedItems: $listedItems";
- }
-
- $data =~ s/\R//g; # Remove new lines
-
- readingsBeginUpdate($hash);
-
- while ($data =~ /{'title':'(.+?)',/g)
- {
-
- $presetName = $1;
- if($data =~ /'id':(.+?),/g)
- {
- $presetID = $1;
- }
- if ($presetID ne "" and $presetName ne "")
- {
- readingsBulkUpdate($hash, sprintf(".inetRadioPreset_%02d", $presetID), $presetName);
- }
- }
- readingsEndUpdate($hash, 1);
- if($presetID < ($hash->{helper}{TOTALINETRADIOPRESETS})) # Maximum listed items = 8. Get the next items by sending the nextreqURL
- {
- # External Command. Not from buffer timer.
- $hash->{helper}{fromSendCommandBuffer} = 0;
- PHILIPS_AUDIO_SendCommand($hash, $nextreqURL, "","getPresets", "noArg");
- }
- else
- {
- readingsSingleUpdate($hash, "playerListStatus", "ready", 1);
- delete $hash->{READINGS}{Reading_presets};
- delete $hash->{READINGS}{readingPresets};
- $hash->{helper}{cmdStep} = 4;
- # Finished
- }
- }
- }
- }
- elsif ($cmd eq "getFavorites")
- {
- $hash->{helper}{TOTALINETRADIOFAVORITES} = 0 if(not defined($hash->{helper}{TOTALINETRADIOFAVORITES}));
-
- # This command must be processed hierarchicaly through the navigation path
- if($hash->{helper}{cmdStep} == 1)
- {
- $hash->{helper}{cmdStep} = 2;
- # Internet radio
- PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$01\$001\$0", "","getFavorites", "noArg");
- }
- elsif($hash->{helper}{cmdStep} == 2)
- {
- $hash->{helper}{cmdStep} = 3;
- # Favorites
- PHILIPS_AUDIO_SendCommand($hash, "/nav\$03\$02\$002\$0", "","getFavorites", "noArg");
- }
- elsif($hash->{helper}{cmdStep} == 3)
- {
- if($data =~ /<title>Error<\/title>/)
- {
- # In case on presets defined the player returns an Error
- # Do nothing
- $hash->{helper}{TOTALINETRADIOFAVORITES} = 0;
- readingsSingleUpdate($hash, "totalFavorites", "0", 1);
- delete $hash->{READINGS}{Reading_favorites};
- }
- else
- {
- my $listedItems; # Visible Items in the display. Max 8
- my $nextreqURL;
- my $i;
- my $favoriteID = 0;
- my $favoriteName;
- # Parse first 8 Presets
- if ($data =~ /'nextrequrl':'(.+?)',/)
- {
- $nextreqURL = $1;
- #Log3 $name, 5, "NextreqURL: $nextreqURL";
- }
- if ($data =~ /'totalListCount':(.+),/)
- {
- $hash->{helper}{TOTALINETRADIOFAVORITES} = $1;
- readingsSingleUpdate($hash, "totalFavorites", $1, 1);
- }
-
- $data =~ s/\R//g; # Remove new lines
-
- readingsBeginUpdate($hash);
-
- while($data =~ /{'title':'(.+?)',/g)
- {
- $favoriteName = $1;
-
- if($data =~ /'id':(.+?),/g)
- {
- $favoriteID = $1;
- }
- if ($favoriteID ne "" and $favoriteName ne "")
- {
- readingsBulkUpdate($hash, sprintf(".inetRadioFavorite_%02d", $favoriteID), $favoriteName);
- }
- }
-
- readingsEndUpdate($hash, 1);
- #Log3 $name, 5, "FavoriteIDNachLoop: $favoriteID";
- if($favoriteID < ($hash->{helper}{TOTALINETRADIOFAVORITES})) # Maximum listed items = 8. Get the next items by sending the nextreqURL
- {
- # External Command. Not from buffer timer.
- $hash->{helper}{fromSendCommandBuffer} = 0;
-
- PHILIPS_AUDIO_SendCommand($hash, $nextreqURL, "","getFavorites", "noArg");
- }
- else
- {
- readingsSingleUpdate($hash, "playerListStatus", "ready", 1);
- delete $hash->{READINGS}{Reading_favorites};
- delete $hash->{READINGS}{readingFavorites};
- $hash->{helper}{cmdStep} = 4;
- # Finished
- }
- }
- }
- }
- elsif($cmd =~ /input|selectStream/)
- {
- $data =~ s/\R//g; # Remove new lines for regex
-
- if($arg eq "---")
- {
- # Do nothing
- }
- elsif($arg =~ /internetRadio|onlineServices|mediaLibrary|(\d{3})_(.+?)_|lvl_(.+?)/) # 000_[c|i]_******
- {
- # don't update menu content if playable item was chosen
- if (defined $1)
- {
- if ($2 eq "i")
- {
- $hash->{helper}{networkRequest} = "idle";
- $hash->{helper}{playerState} = "playing";
- # Stream selected. Manual operation finished.
- $hash->{helper}{manualOperation} = 0;
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate ($hash, "networkRequest", "idle");
- readingsBulkUpdate ($hash, "playerListStatus", "ready");
- readingsBulkUpdate ($hash, "playerState", "playing");
- readingsBulkUpdate ($hash, ".manualOperation", "no");
- readingsEndUpdate ($hash, 1);
-
- PHILIPS_AUDIO_SendCommand($hash, "/nowplay", "","nowplay", "noArg");
-
- # Stream selected trigger getStatus
- PHILIPS_AUDIO_ResetTimer($hash); # getStatus
- return;
- }
- }
-
- if ($data =~ /{'command':'NOTHING','value':0}|<title>Error<\/title>/)
- {
- my $errorMessage = "Player responded with unspecified error";
-
- if($data =~ /alert\(\'(.*?)\'\);|\'command\':\'(.*?)\'/)
- {
- $errorMessage = $1;
- }
- # Delete old readings
- delete $hash->{READINGS}{$_} foreach (grep /listItem_...$/, keys %{$hash->{READINGS}});
- delete $hash->{READINGS}{$_} foreach (grep /.listItemTarget_...$/, keys %{$hash->{READINGS}});
-
- $hash->{helper}{networkRequest} = "idle";
- $hash->{helper}{manualOperation} = 0;
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate ($hash, "networkRequest", "idle");
- readingsBulkUpdate ($hash, "listItem_001", "$errorMessage");
- readingsBulkUpdate ($hash, ".listItemTarget_001", "$hash->{helper}{currentNavUrl}");
- readingsBulkUpdate ($hash, "playerListStatus", "ready");
- readingsBulkUpdate ($hash, ".manualOperation", "no");
- readingsEndUpdate ($hash, 1);
-
- return "Player response: $errorMessage.";
- }
-
- my $listDepthLevel = 0;
- my $playerListTotalCount = 0;
- my $listId = 0;
- my $listItems = "";
-
- readingsBeginUpdate($hash);
-
- if($data =~ /var listdetails = \{(.*)\};/)
- {
- my $listdetails_temp = $1;
- my $listdetails = $listdetails_temp;
-
- if($listdetails =~ /'totalitems':(.*?),/)
- {
- readingsBulkUpdate($hash, ".listTotalItems", "$1");
- }
-
- $listdetails = $listdetails_temp;
-
- if($listdetails =~ /'totalListCount':(.*?),/)
- {
- $playerListTotalCount = $1;
- $hash->{helper}{playerListTotalCount} = $1;
- readingsBulkUpdate($hash, "playerListTotalCount", "$1");
- }
-
- $listdetails = $listdetails_temp;
-
- if($listdetails =~ /'depthlevel':(.*?),/)
- {
- $listDepthLevel = $1;
- readingsBulkUpdate($hash, ".listDepthLevel", "$1");
- }
- }
-
- if($data =~ /var listItem = \{(.*)\};/)
- {
- my $listItems_temp = $1;
- $listItems = $listItems_temp;
-
- if($listItems =~ /'nextrequrl':'(.*?)'/)
- {
- $hash->{helper}{nextUrl} = $1;
- readingsBulkUpdate($hash, ".listNextUrl", "$1");
- }
-
- $listItems = $listItems_temp;
-
- if($listItems =~ /'prevUrl':'(.*?)',/)
- {
- if($1 ne "")
- {
- $hash->{helper}{prevUrl} = $1;
- readingsBulkUpdate($hash, ".listPrevUrl", "$1");
- }
- else
- {
- $hash->{helper}{prevUrl} = "-";
- readingsBulkUpdate($hash, ".listPrevUrl", "-");
- }
- }
-
- readingsEndUpdate($hash, 1);
-
- $listItems = $listItems_temp;
-
- if($listItems =~ /'items': \[(.*)\]/)
- {
-
- # Delete old readings
- delete $hash->{READINGS}{$_} foreach (grep /listItem_...$/, keys %{$hash->{READINGS}});
- delete $hash->{READINGS}{$_} foreach (grep /.listItemTarget_...$/, keys %{$hash->{READINGS}});
-
- # Predefine all listItem readings with "reading..."
-
- readingsBeginUpdate($hash);
-
- for(my $i = 1; ($i < int($hash->{helper}{playerListTotalCount}) + 1) and ($i < AttrVal($name, "maxListItems", 100) + 1); $i++)
- {
- readingsBulkUpdate($hash, "listItem_".sprintf("%03s", $i), "reading...");
- }
-
- my $items = $1;
-
- while ($items =~ /\{(.*?)\}/g)
- {
- my $item = $1;
- my $title = "";
-
- if($item =~ /'title':'(.*?)',/)
- {
- $title = PHILIPS_AUDIO_html2txt($1);
- }
-
- if($item =~ /'id':(.*?),/)
- {
- $listId = $1;
- }
-
- my $itemTarget = "";
- if($item =~ /'target':'(.*?)'/)
- {
- $itemTarget = $1;
- readingsBulkUpdate($hash, ".listItemTarget_".sprintf("%03s", int($listId)), $1);
- }
- if(substr($itemTarget, -1) eq "1")
- {
- $title = "i_" . $title; # item
- }
- else
- {
- $title = "c_" . $title; # container
- }
- readingsBulkUpdate($hash, "listItem_".sprintf("%03s", int($listId)), $title);
- }
-
- readingsEndUpdate($hash, 1);
-
- }
- }
- if($listId < $hash->{helper}{playerListTotalCount})
- {
- # External Command. Not from buffer timer.
- $hash->{helper}{fromSendCommandBuffer} = 0;
- PHILIPS_AUDIO_SendCommand($hash, "$hash->{helper}{nextUrl}", "", "selectStream", "list");
- }
- else
- {
- $hash->{helper}{networkRequest} = "idle";
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate ($hash, "networkRequest", "idle");
- readingsBulkUpdate ($hash, "playerListStatus", "ready");
- readingsEndUpdate ($hash, 1);
-
- }
- }
- elsif($arg =~ /list/)
- {
- if ($data =~ /{'command':'NOTHING','value':0}|<title>Error<\/title>/)
- {
- $hash->{helper}{networkRequest} = "idle";
- readingsSingleUpdate($hash, "networkRequest", "idle", 1);
- Log3 $name, 3, "PHILIPS_AUDIO ($name) - Player response: Media Library change not successful.";
- return "Player response: Media Library change not successful.";
- }
-
- $hash->{helper}{networkRequest} = "busy";
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash, "networkRequest", "busy");
-
- $data =~ s/\R//g; # Remove new lines for regex
-
- my $listDepthLevel = 0;
- my $playerListTotalCount = 0;
- my $listId = 0;
- my $listItems = "";
-
- $listItems = $data;
-
- if($listItems =~ /'nextrequrl':'(.*?)'/)
- {
- $hash->{helper}{nextUrl} = $1;
- readingsBulkUpdate($hash, ".listNextUrl", "$1");
- }
-
- $listItems = $data;
-
- if($listItems =~ /'prevUrl':'(.*?)',/)
- {
- if($1 ne "")
- {
- $hash->{helper}{prevUrl} = $1;
- readingsBulkUpdate($hash, ".listPrevUrl", "$1");
- }
- else
- {
- $hash->{helper}{prevUrl} = "-";
- readingsBulkUpdate($hash, ".listPrevUrl", "-");
- }
- }
-
- $listItems = $data;
-
- if($listItems =~ /'items': \[(.*)\]/)
- {
- my $items = $1;
-
- while ($items =~ /\{(.*?)\}/g)
- {
- my $item_temp = $1;
- my $item = $item_temp;
-
- my $title = "";
- if($item =~ /'title':'(.*?)',/)
- {
- $title = PHILIPS_AUDIO_html2txt($1);
- }
- $item = $item_temp;
- if($item =~ /'id':(.*?),/)
- {
- $listId = $1;
- }
-
- $item = $item_temp;
- my $itemTarget = "";
- if($item =~ /'target':'(.*?)'/)
- {
- $itemTarget = $1;
- readingsBulkUpdate($hash, ".listItemTarget_".sprintf("%03s", int($listId)), $1);
- }
-
- if(substr($itemTarget, -1) eq "1")
- {
- $title = "i_" . $title; # item
- }
- else
- {
- $title = "c_" . $title; # container
- }
- readingsBulkUpdate($hash, "listItem_".sprintf("%03s", int($listId)), $title);
-
- last if($listId eq AttrVal($name, "maxListItems", 100));
- }
- }
-
- if(($listId < $hash->{helper}{playerListTotalCount}) && ($listId < AttrVal($name, "maxListItems", 100)))
- {
- # External Command. Not from buffer timer.
- $hash->{helper}{fromSendCommandBuffer} = 0;
-
- PHILIPS_AUDIO_SendCommand($hash, "$hash->{helper}{nextUrl}", "", "selectStream", "list");
- }
- else
- {
- $hash->{helper}{networkRequest} = "idle";
- readingsBulkUpdate($hash, "networkRequest", "idle");
- readingsBulkUpdate($hash, "playerListStatus", "ready");
- }
-
- readingsEndUpdate($hash, 1);
- }
-
- }
-
- $hash->{helper}{networkRequest} = "idle";
- readingsSingleUpdate($hash, "networkRequest", "idle", 1);
- }
- return;
- }
- #############################
- # converts straight volume in percentage volume (volumestraightmin .. volumestraightmax => 0 .. 100%)
- sub PHILIPS_AUDIO_volume_rel2abs
- {
- my ($hash, $percentage) = @_;
-
- return int($percentage * 64 / 100);
- }
- #############################
- # converts relative volume to "straight" volume (0 .. 100% => volumestraightmin .. volumestraightmax)
- sub PHILIPS_AUDIO_volume_abs2rel
- {
- my ($hash, $absolute) = @_;
-
- return int($absolute * 100 / 64);
- }
- #############################
- # Restarts the internal status request timer according to the given interval or current receiver state
- sub PHILIPS_AUDIO_ResetTimer
- {
- my ($hash, $interval) = @_;
- RemoveInternalTimer($hash, "PHILIPS_AUDIO_GetStatus");
- if($hash->{helper}{DISABLED} == 0)
- {
- if(defined($interval))
- {
- InternalTimer(gettimeofday() + $interval, "PHILIPS_AUDIO_GetStatus", $hash);
- }
- elsif((exists($hash->{READINGS}{presence}{VAL}) and $hash->{READINGS}{presence}{VAL} eq "present") and (exists($hash->{READINGS}{power}{VAL}) and $hash->{READINGS}{power}{VAL} eq "on"))
- {
- InternalTimer(gettimeofday() + $hash->{helper}{ON_INTERVAL}, "PHILIPS_AUDIO_GetStatus", $hash);
- }
- else
- {
- InternalTimer(gettimeofday() + $hash->{helper}{OFF_INTERVAL}, "PHILIPS_AUDIO_GetStatus", $hash);
- }
- }
- return;
- }
- #############################
- # convert all HTML entities into UTF-8 equivalent
- sub PHILIPS_AUDIO_html2txt
- {
- my ($string) = @_;
- $string =~ s/(&amp;quot;|&quot;|"|\\")/\"/g;
- $string =~ s/(&amp;|&)/&/g;
- $string =~ s/ / /g;
- $string =~ s/('|\\'|\')/'/g;
- $string =~ s/(\xe4|ä)/ä/g;
- $string =~ s/(\xc4|Ä)/Ä/g;
- $string =~ s/(\xf6|ö)/ö/g;
- $string =~ s/(\xd6|Ö)/Ö/g;
- $string =~ s/(\xfc|ü)/ü/g;
- $string =~ s/(\xdc|Ü)/Ü/g;
- $string =~ s/(\xdf|ß)/ß/g;
- return $string;
- }
- sub PHILIPS_AUDIO_getMediaRendererDesc
- {
- # queries the addition model descriptions
- my ($hash) = @_;
-
- my $name = $hash->{NAME};
-
- Log3 $name, 5, "PHILIPS_AUDIO ($name) - execute nonblocking \"MediaRendererDesc\"";
-
- my $url = "";
- my $port = "";
-
- if(uc($hash->{MODEL}) eq "NP3700")
- {
- $url = "http://$hash->{IP_ADDRESS}:7123/DeviceDescription.xml";
- }
- elsif
- (
- (uc($hash->{MODEL}) eq "NP3500") or
- (uc($hash->{MODEL}) eq "NP3900") or
- (uc($hash->{MODEL}) eq "AW9000")
- )
- {
- $url = "http://$hash->{IP_ADDRESS}:49153/nmrDescription.xml";
- }
- else
- {
- return "Unknown Device.";
- }
-
- HttpUtils_NonblockingGet({
- url => $url,
- timeout => AttrVal($name, "requestTimeout", 10),
- noshutdown => 1,
- data => "",
- loglevel => ($hash->{helper}{AVAILABLE} ? undef : 5),
- hash => $hash,
- cmd => "getMediaRendererDesc",
- arg => "noArg",
- callback => \&PHILIPS_AUDIO_ParseResponse
- });
- return;
- }
- 1;
- =pod
- =item device
- =item summary controls a Philips Streamium Network Player in a local network
- =item summary_DE steuert einen Philips Streamium Netzwerkplayer im lokalen Netzwerk
- =begin html
- <a name="PHILIPS_AUDIO"></a>
- <h3>PHILIPS_AUDIO</h3>
- <ul>
- <a name="PHILIPS_AUDIOdefine"></a>
- <b>Define</b>
- <br><br>
- <ul>
- <code>
- define <name> PHILIPS_AUDIO <device model> <ip-address> [<status_interval>]<br><br>
- define <name> PHILIPS_AUDIO <device model> [<off_status_interval>] [<on_status_interval>]
- </code>
- <br><br>
- This module controls a Philips Audio Player e.g. MCi, Streamium or Fidelio and potentially any other device controlled by the "myRemote" app.<br>
- You might also check, opening the following URL in the browser: http://[ip number of your device]:8889/index
- <br><br>
- (Tested on: AW9000, NP3500, NP3700 and NP3900)
- <br><br>
- Example:<br><br>
- <ul>
- <code>
- define player PHILIPS_AUDIO NP3900 192.168.0.15<br><br>
- # With custom status interval of 60 seconds<br>
- define PHAUDIO_player PHILIPS_AUDIO NP3900 192.168.0.15 <b>60</b><br><br>
- # With custom "off"-interval of 60 seconds and "on"-interval of 10 seconds<br>
- define PHAUDIO_player PHILIPS_AUDIO NP3900 192.168.0.15 <b>60 10</b><br>
- </code>
- <br>
- <i>Note: Due to slow command processing by the player itself the minimum interval is <b>limited to 5 seconds</b>. More frequent polling might cause device freezes.</i>
- </ul>
- </ul>
- <br>
- <a name="PHILIPS_AUDIOset"></a>
- <b>Set</b>
- <ul>
- <code>
- set <name> <command> [<parameter>]
- </code><br><br>
- <i>Note: Commands and parameters are case sensitive.</i><br>
- <ul><br>
- <li><b>favoriteAdd</b> – Adds currently played Internet Radio stream to favorites</li>
- <li><b>favoriteRemove</b> – Removes currently played Internet Radio stream from favorites</li>
- <li><b>getFavorites</b> – Reads stored favorites from the device (may take some time...)</li>
- <li><b>getMediaRendererDesc</b> – Reads device specific information (stored in the deviceInfo reading)</li>
- <li><b>getPresets</b> – Reads stored presets from the device (may take some time...)</li>
- <li><b>input</b> – Selects the following input</li>
- <ul>
- <li><b>analogAux</b> – Selects the analog AUX input (AW9000 only)</li>
- <li><b>digital1Coaxial</b> – Selects the digital coaxial input (AW9000 only)</li>
- <li><b>digital2Optical</b> – Selects the digital optical input (AW9000 only)</li>
- <li><b>internetRadio</b> – Selects the Internet Radio input</li>
- <li><b>mediaLibrary</b> – Selects the Media Library input (UPnP/DLNA server) (not available on AW9000)</li>
- <li><b>mp3Link</b> – Selects the analog MP3 Link input (not available on AW9000)</li>
- <li><b>onlineServices</b> – Selects the Online Services input</li>
- </ul>
- <li><b>mute [ on | off ]</b> – Mutes/unmutes the device</li>
- <li><b>player</b> – Player related commands</li>
- <ul>
- <li><b>next</b> – Selects next audio stream</li>
- <li><b>prev</b> – Selects previous audio stream</li>
- <li><b>play-pause</b> – Plays/pauses the current audio stream</li>
- <li><b>stop</b> – Stops the current audio stream</li>
- </ul>
- <li><b>repeat [ single | all | off]</b> – Selects the repeate mode</li>
- <li><b>selectFavorite [ name ]</b> – Selects a favorite. Empty if no favorites found. (see also getFavorites)</li>
- <li><b>selectFavoriteByNumber [ number ]</b> – Selects a favorite by its number. Empty if no favorites found. (see also getFavorites)</li>
- <li><b>selectPreset [ name ]</b> – Selects a preset. Empty if no presets found. (see also getPresets)</li>
- <li><b>selectPresetByNumber [ number ]</b> – Selects a preset by its number. Empty if no presets found. (see also getPresets)</li>
- <li><b>selectStream [ name ]</b> – Context-sensitive. Selects a stream depending on the current input and player list content. A 'c'-prefix represents a 'container' (directory). An 'i'-prefix represents an 'item' (audio stream).</li>
- <li><b>shuffle [ on | off ]</b> – Sets the shuffle mode</li>
- <li><b>standbyButton</b> – Emulates the standby button. Toggles between standby and power on</li>
- <li><b>volume</b> – Sets the relative volume 0...100%</li>
- <li><b>volumeDown</b> – Sets the device specific volume by one decrement</li>
- <li><b>volumeStraight</b> – Sets the device specific absolute volume 0...64</li>
- <li><b>volumeUp</b> – Sets the device specific volume by one increment</li>
- </ul>
- </ul>
- <br>
- <a name="PHILIPS_AUDIOget"></a>
- <b>Get</b>
- <ul>
- <code>
- get <name> <reading> <reading name>
- </code>
- <ul>
- <br>
- <li><b>deviceInfo</b> – Returns device specific information</li>
- <li><b>reading</b></li>
- <ul>
- <li><b>input</b> – Returns current input or '-' if not playing</li>
- <li><b>listItem_xxx</b> – Returns player list item (limited to 999 entries)</li>
- <li><b>networkError</b> – Shows an occured current network error</li>
- <li><b>networkRequest</b> – Shows current network activity (idle/busy)</li>
- <li><b>power</b> – Returns power status (on/off)</li>
- <li><b>playerAlbum</b> – Returns the album name of played stream</li>
- <li><b>playerAlbumArt</b> – Returns the album art of played audio stream</li>
- <li><b>playerListStatus</b> – Returns current player list status (busy/ready)</li>
- <li><b>playerListTotalCount</b> – Returns number of player list entries</li>
- <li><b>playerPlayTime</b> – Returns audio stream duration</li>
- <li><b>playerPlaying</b> – Returns current player playing state (yes/no)</li>
- <li><b>playerRadioStation</b> – Returns the name of played radio station</li>
- <li><b>playerRadioStationInfo</b> – Returns additional info of the played radio station</li>
- <li><b>playerRepeat</b> – Returns current repeat mode (off/single/all)</li>
- <li><b>playerShuffle</b> – Returns current shuffle mode (on/off)</li>
- <li><b>playerState</b> – Returns current player state (home/browsing/playing)</li>
- <li><b>playerStreamFavorite</b> – Shows if audio stream is a favorite (yes/no)</li>
- <li><b>playerStreamRating</b> – Shows rating of the audio stream</li>
- <li><b>playerTitle</b> – Returns audio stream's title</li>
- <li><b>playerTotalTime</b> – Shows audio stream's total time</li>
- <li><b>presence</b> – Returns peresence status (present/absent)</li>
- <li><b>state</b> – Returns current state (on/off)</li>
- <li><b>totalFavorites</b> – Returns total number of stored favorites (see getFavorites)</li>
- <li><b>totalPresets</b> – Returns total number of stored presets (see getPresets)</li>
- <li><b>volume</b> – Returns current relative volume (0...100%)</li>
- <li><b>volumeStraight</b> – Returns current device absolute volume (0...64)</li>
- </ul>
- </ul>
- <br>
- </ul>
- <a name="PHILIPS_AUDIOattr"></a>
- <b>Attributes</b><br><br>
- <ul>
- <ul>
- <li><b>autoGetFavorites</b> – Automatically read favorites from device if none available (default off)</li>
- <li><b>autoGetPresets</b> – Automatically read presets from device if none available (default off)</li>
- <li><b>do_not_notify</b></li>
- <li><b>httpBufferTimeout</b> – Optional attribute defing the internal http buffer timeount (default 10)</li>
- <li><b>maxListItems</b> – Defines max. number of player list items (default 100)</li>
- <li><b>playerBrowsingTimeout</b> – Defines the inactivity timeout for browsing. After that timeout the player returns to the state 'home' in which the readings are updated automaically again. (default 180 seconds)</li>
- <li><b>readingFnAttributes</b></li>
- <li><b>requestTimeout</b> – Optional attribute defining the http response timeout (default 4 seconds)</li>
- </ul>
- </ul>
- <br>
- </ul>
- =end html
- =begin html_DE
- <a name="PHILIPS_AUDIO"></a>
- <h3>PHILIPS_AUDIO</h3>
- <ul>
- <a name="PHILIPS_AUDIOdefine"></a>
- <b>Define</b><br><br>
- <ul>
- <code>
- define <name> PHILIPS_AUDIO <device model> <ip-address> [<status_interval>]<br><br>
- define <name> PHILIPS_AUDIO <device model> [<off_status_interval>] [<on_status_interval>]
- </code>
- <br><br>
- Mit Hilfe dieses Moduls lassen sich Philips Audio Netzwerk Player wie z.B. MCi, Streamium oder Fidelio im lokalen Netzwerk steuern.<br>
- Geräte, die über die myRemote App oder einen internen HTTP Server am Port 8889 sollten theoretisch ebenfalls bedient werden können.<br>
- (http://[ip Nummer des Gerätes]:8889/index)<br>
- <br>
- (Getestet mit: AW9000, NP3500, NP3700 und NP3900)
- <br><br>
- Beispiel:<br>
- <ul><br>
- <code>
- define PHAUDIO_player PHILIPS_AUDIO NP3900 192.168.0.15
- <br>
- <br>
- # 60 Sekunden Intervall<br>
- define PHAUDIO_player PHILIPS_AUDIO NP3900 192.168.0.15 <b>60</b>
- <br>
- <br>
- # 60 Sekunden Intervall für "off" und 10 Sekunden für "on"<br>
- define PHAUDIO_player PHILIPS_AUDIO NP3900 192.168.0.15 <b>60 10</b>
- </code>
- <br><br>
- <i>Bemerkung: Aufgrund der relativ langsamen Verarbeitung von Befehlen durch den Player selbst wurde das minimale Intervall <b>auf 5 Sekunden limitiert</b>. Dadurch sollten potentielle Gerätefreezes reduziert werden.</i>
- </ul>
- </ul><br>
- <a name="PHILIPS_AUDIOset"></a>
- <b>Set</b>
- <ul>
- <code>
- set <name> <command> [<parameter>]
- </code>
- <br><br>
- <i>Bemerkung: Befehle und Parameter sind case-sensitive</i><br>
- <ul><br>
- <li><b>favoriteAdd</b> – Fügt den aktuellen Audiostream zu Favoriten hinzu</li>
- <li><b>favoriteRemove</b> – Löscht den aktuellen Audiostream aus den Favoriten</li>
- <li><b>getFavorites</b> – Liest aus die gespeicherten Favoriten aus dem Gerät (kann einige Zeit dauern...)</li>
- <li><b>getMediaRendererDesc</b> – Liest aus Gerätspezifische Informationen aus (siehe auch deviceInfo reading)</li>
- <li><b>getPresets</b> – Liest aus die gespeicherten Presets aus dem Gerät (kann einige Zeit dauern...)</li>
- <li><b>input</b> – Schaltet auf den folgenden Eingang</li>
- <ul>
- <li><b>analogAux</b> – AUX input (nur AW9000)</li>
- <li><b>digital1Coaxial</b> – digital coaxial input (nur AW9000)</li>
- <li><b>digital2Optical</b> – digital optical input (nur AW9000)</li>
- <li><b>internetRadio</b> – Internet Radio</li>
- <li><b>mediaLibrary</b> – Media Library (UPnP/DLNA server) (nicht verfügbar beim AW9000)</li>
- <li><b>mp3Link</b> – Analoger MP3 Link (nicht verfügbar beim AW9000)</li>
- <li><b>onlineServices</b> – Online Services</li>
- </ul>
- <li><b>mute [ on | off ]</b> – Stummschaltung (an/aus)</li>
- <li><b>player</b> – Player-Befehle</li>
- <ul>
- <li><b>next</b> – Nächstee Audiostream</li>
- <li><b>prev</b> – Letzter Audiostream</li>
- <li><b>play-pause</b> – Play/pause des aktuellen Audiostreams</li>
- <li><b>stop</b> – Stoppt das Abspielen des aktuellen Audiostreams</li>
- </ul>
- <li><b>repeat [ single | all | off]</b> – Stellt den repeat mode ein</li>
- <li><b>selectFavorite [ name ]</b> – Wählt einen Favoriten. Leer falls keine Favoriten vorhanden (s. getFavorites)</li>
- <li><b>selectFavoriteByNumber [ number ]</b> – Wählt einen Favoriten anhand seiner Speichernummer. Leer falls keine Favoriten vorhanden (s. getFavorites)</li>
- <li><b>selectPreset [ name ]</b> – Wählt einen Preset. Leer falls keine Presets vorhanden (s. getPresets)</li>
- <li><b>selectPresetByNumber [ number ]</b> – Wählt einen Preset anhand seiner Speichernummer. Leer falls keine Presets vorhanden (see also getPresets)</li>
- <li><b>selectStream [ name ]</b> – Context-sensitive. Wählt einen Audiostream. Hängt vom aktuellen Inhalt der Playerlist ab. Ein 'c'-Präfix repräsentiert einen 'Container' (Directory). ein 'i'-Präfix repräsentiert ein 'Item' (audio stream).</li></li>
- <li><b>shuffle [ on | off ]</b> – Wählt den gewünschten Shuffle Modus</li>
- <li><b>standbyButton</b> – Emuliert den standby-Knopf. Toggelt zwischen standby und power on</li>
- <li><b>volume</b> – Setzt die relative Lautstärke 0...100%</li>
- <li><b>volumeDown</b> – Setzt die Lautstärke um ein Dekrement herunter</li>
- <li><b>volumeStraight</b> – Setzt die devicespezifische Lautstärke 0...64</li>
- <li><b>volumeUp</b> – Setzt die Lautstärke um ein Inkrement herauf</li>
- </ul>
- </ul>
- <br>
- <a name="PHILIPS_AUDIOget"></a>
- <b>Get</b>
- <ul>
- <code>
- get <name> <reading> <reading name>
- </code>
- <ul>
- <br>
- <li><b>deviceInfo</b> – Liefert devicespezifische Information</li>
- <li><b>reading</b></li>
- <ul>
- <li><b>input</b> – Liefert den aktuellen Eingang oder '-' falls kein Audiostream aktiv</li>
- <li><b>listItem_xxx</b> – Liefert Einträge der Playerliste (limitiert auf 999 Einträge)</li>
- <li><b>networkError</b> – Liefert einen potentiellen Netzwerkfehler</li>
- <li><b>networkRequest</b> – Liefert die aktuelle Netzwerkaktivität (idle/busy)</li>
- <li><b>power</b> – Liefert den Power-Status (on/off)</li>
- <li><b>playerAlbum</b> – Liefert den Albumnamen des aktiven Audiostreams</li>
- <li><b>playerAlbumArt</b> – Liefert die Albumart des aktiven Audiostreams</li>
- <li><b>playerListStatus</b> – Liefert den aktuellen Zusatand der Playlist (busy/ready)</li>
- <li><b>playerListTotalCount</b> – Liefert die Anzahl der Playlisteinträge</li>
- <li><b>playerPlayTime</b> – Liefert die aktuell Audiostreamspieldauer</li>
- <li><b>playerPlaying</b> – Zeigt an, ob Audiostream abgespielt wird (yes/no)</li>
- <li><b>playerRadioStation</b> – Liefert den Stationsnamen des Radiosenders</li>
- <li><b>playerRadioStationInfo</b> – Liefert zusätzliche Informationen des Radiosenders</li>
- <li><b>playerRepeat</b> – Zeigt den Reapeat Mode an (off/single/all)</li>
- <li><b>playerShuffle</b> – Zeigt den aktuellen Shuffle mode an (on/off)</li>
- <li><b>playerState</b> – Zeigt den Playerzustand an (home/browsing/playing)</li>
- <li><b>playerStreamFavorite</b> – Zeigt an, ob aktueller Audiostream ein Favorit ist (yes/no)</li>
- <li><b>playerStreamRating</b> – Zeigt das rating des Audiostreams</li>
- <li><b>playerTitle</b> – Zeigt den Titel des Audiostreams an</li>
- <li><b>playerTotalTime</b> – Zeigt die Audiostreamdauer an</li>
- <li><b>presence</b> – Liefert den presence status (present/absent)</li>
- <li><b>state</b> – Lifert den aktuellen Gerätestatus (on/off)</li>
- <li><b>totalFavorites</b> – Liefert die Anzahl gepseicherter Favoriten (s. getFavorites)</li>
- <li><b>totalPresets</b> – Liefert die Anzahl gepseicherter Presets (see getPresets)</li>
- <li><b>volume</b> – Liefert die relative Lutstärke (0...100%)</li>
- <li><b>volumeStraight</b> – Liefert die devicespezifische Lautstärke (0...64)</li>
- </ul>
- </ul>
- <br>
- </ul>
- <a name="PHILIPS_AUDIOattr"></a>
- <b>Attribute</b><br><br>
- <ul>
- <ul>
- <li><b>autoGetFavorites</b> – Automatisches Auslesen der Favoriten beim Modulstart falls keine vorhanden (default off)</li>
- <li><b>autoGetPresets</b> – Automatisches Auslesen der Presets beim Modulstart falls keine vorhanden (default off)</li>
- <li><b>do_not_notify</b></li>
- <li><b>httpBufferTimeout</b> – Optionalles Attribut für den internen http buffer timeount (default 10 Sekunden)</li>
- <li><b>maxListItems</b> – Definiert die max. Anzahl der anzuzeigenden Playerlisteinträge (default 100)</li>
- <li><b>playerBrowsingTimeout</b> – Definiert den Inaktivitäts-Timeout beim Browsen der Playerlist. Nach diesem Timeout fällt das Modul in den "home"-State zurück. Die Playerreadings werden wieder aktualisiert (default 180 Sekunden)</li>
- <li><b>readingFnAttributes</b></li>
- <li><b>requestTimeout</b> – Optionalles Attribut für http responses (default 4 Sekunden)</li>
- </ul>
- </ul>
- </ul>
- =end html_DE
- =cut
|