mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 06:39:11 +00:00
98_GOOGLECAST: first release
git-svn-id: https://svn.fhem.de/fhem/trunk@14881 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
29e14195f2
commit
32d16099c9
@ -1,5 +1,6 @@
|
||||
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
||||
# Do not insert empty lines here, update check depends on it.
|
||||
- new: 98_GOOGLECAST: first release, read commandref for requirements
|
||||
- changed: 74_AMADautomagicFlowset_4.0.3.xml: workaround for better auto
|
||||
flowsetupdate
|
||||
- feature: 74_AMADDevice: 4.0.5 - Support für NFC and scanning NFC TagId
|
||||
|
649
fhem/FHEM/98_GOOGLECAST.pm
Executable file
649
fhem/FHEM/98_GOOGLECAST.pm
Executable file
@ -0,0 +1,649 @@
|
||||
#############################################################
|
||||
#
|
||||
# GOOGLECAST.pm (c) by Dominik Karall, 2016-2017
|
||||
# dominik karall at gmail dot com
|
||||
# $Id$
|
||||
#
|
||||
# FHEM module to communicate with Google Cast devices
|
||||
# e.g. Chromecast Video, Chromecast Audio, Google Home
|
||||
#
|
||||
# Version: 2.0.0
|
||||
#
|
||||
#############################################################
|
||||
#
|
||||
# v2.0.0 - 20170812
|
||||
# - CHANGE: renamed to 98_GOOGLECAST.pm
|
||||
# - CHANGE: removed favoriteName_X attribute, it was never used
|
||||
# - BUGFIX: updated commandref with further required packages
|
||||
#
|
||||
# v1.0.7 - 20170804
|
||||
# - BUGFIX: fix reconnection in some cases
|
||||
#
|
||||
# v1.0.6 - 20170705
|
||||
# - BUGFIX: speed up youtube video URL extraction with youtube_dl
|
||||
# - BUGFIX: fixed one more issue when chromecast offline
|
||||
# - BUGFIX: improved performance by adding socket to FHEM main loop
|
||||
#
|
||||
# v1.0.5 - 20170704
|
||||
# - BUGFIX: hopefuly fixed the annoying hangs when chromecast offline
|
||||
# - FEATURE: add presence reading (online/offline)
|
||||
#
|
||||
# v1.0.4 - 20170101
|
||||
# - FEATURE: support all services supported by youtube-dl
|
||||
# https://github.com/rg3/youtube-dl/blob/master/docs/supportedsites.md
|
||||
# playlists not yet supported!
|
||||
# - BUGFIX: support non-blocking chromecast search
|
||||
#
|
||||
# v1.0.3 - 20161219
|
||||
# - FEATURE: support volume
|
||||
# - FEATURE: add new readings and removed
|
||||
# castStatus, mediaStatus reading
|
||||
# - FEATURE: add attribute favoriteURL_[1-5]
|
||||
# - FEATURE: add playFavorite [1-5] set function
|
||||
# - FEATURE: retry init chromecast every 10s if not found on startup
|
||||
# - BUGFIX: support special characters for device name
|
||||
#
|
||||
# v1.0.2 - 20161216
|
||||
# - FEATURE: support play of every mime type which is supported
|
||||
# by Chromecast (see https://developers.google.com/cast/docs/media)
|
||||
# including youtube URLs
|
||||
# - CHANGE: change play* methods to play <url>
|
||||
# - FEATURE: support very simple .m3u which contain only URL
|
||||
# - BUGFIX: non-blocking playYoutube
|
||||
# - BUGFIX: fix play if media player is already running
|
||||
#
|
||||
# v1.0.1 - 20161211
|
||||
# - FEATURE: support playYoutube <youtubelink>
|
||||
#
|
||||
# v1.0.0 - 20161015
|
||||
# - FEATURE: first public release
|
||||
#
|
||||
# TODO
|
||||
# - check spotify integration
|
||||
# - support youtube playlists
|
||||
#
|
||||
# NOTES
|
||||
# def play_media(self, url, content_type, title=None, thumb=None,
|
||||
# current_time=0, autoplay=True,
|
||||
# stream_type=STREAM_TYPE_BUFFERED,
|
||||
# metadata=None, subtitles=None, subtitles_lang='en-US',
|
||||
# subtitles_mime='text/vtt', subtitle_id=1):
|
||||
# """
|
||||
# Plays media on the Chromecast. Start default media receiver if not
|
||||
# already started.
|
||||
# Parameters:
|
||||
# url: str - url of the media.
|
||||
# content_type: str - mime type. Example: 'video/mp4'.
|
||||
# title: str - title of the media.
|
||||
# thumb: str - thumbnail image url.
|
||||
# current_time: float - seconds from the beginning of the media
|
||||
# to start playback.
|
||||
# autoplay: bool - whether the media will automatically play.
|
||||
# stream_type: str - describes the type of media artifact as one of the
|
||||
# following: "NONE", "BUFFERED", "LIVE".
|
||||
# subtitles: str - url of subtitle file to be shown on chromecast.
|
||||
# subtitles_lang: str - language for subtitles.
|
||||
# subtitles_mime: str - mimetype of subtitles.
|
||||
# subtitle_id: int - id of subtitle to be loaded.
|
||||
# metadata: dict - media metadata object, one of the following:
|
||||
# GenericMediaMetadata, MovieMediaMetadata, TvShowMediaMetadata,
|
||||
# MusicTrackMediaMetadata, PhotoMediaMetadata.
|
||||
# Docs:
|
||||
# https://developers.google.com/cast/docs/reference/messages#MediaData
|
||||
# """
|
||||
#
|
||||
#############################################################
|
||||
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Blocking;
|
||||
use Encode;
|
||||
use SetExtensions;
|
||||
|
||||
use LWP::UserAgent;
|
||||
|
||||
sub GOOGLECAST_Initialize($) {
|
||||
my ($hash) = @_;
|
||||
|
||||
$hash->{DefFn} = 'GOOGLECAST_Define';
|
||||
$hash->{UndefFn} = 'GOOGLECAST_Undef';
|
||||
$hash->{GetFn} = 'GOOGLECAST_Get';
|
||||
$hash->{SetFn} = 'GOOGLECAST_Set';
|
||||
$hash->{ReadFn} = 'GOOGLECAST_Read';
|
||||
$hash->{AttrFn} = 'GOOGLECAST_Attribute';
|
||||
$hash->{AttrList} = "favoriteURL_1 favoriteURL_2 favoriteURL_3 favoriteURL_4 ".
|
||||
"favoriteURL_5 ".$readingFnAttributes;
|
||||
|
||||
Log3 $hash, 3, "GOOGLECAST: GoogleCast v2.0.0";
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub GOOGLECAST_Define($$) {
|
||||
my ($hash, $def) = @_;
|
||||
my @a = split("[ \t]+", $def);
|
||||
my $name = $a[0];
|
||||
|
||||
$hash->{STATE} = "initialized";
|
||||
|
||||
if (int(@a) > 3) {
|
||||
return 'GOOGLECAST: Wrong syntax, must be define <name> GOOGLECAST <device name>';
|
||||
} elsif(int(@a) == 3) {
|
||||
Log3 $hash, 3, "GOOGLECAST: $a[2] initializing...";
|
||||
$hash->{CCNAME} = $a[2];
|
||||
GOOGLECAST_updateReading($hash, "presence", "offline");
|
||||
GOOGLECAST_initDevice($hash);
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub GOOGLECAST_findChromecasts {
|
||||
my ($string) = @_;
|
||||
my ($name) = split("\\|", $string);
|
||||
my $result = "$name";
|
||||
|
||||
my @ccResult = GOOGLECAST_findChromecastsPython();
|
||||
foreach my $ref_cc (@ccResult) {
|
||||
my @cc = @$ref_cc;
|
||||
$result .= "|CCDEVICE|".$cc[0]."|".$cc[1]."|".$cc[2]."|".$cc[3]."|".$cc[4];
|
||||
}
|
||||
Log3 $name, 4, "GOOGLECAST: search result: $result";
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub GOOGLECAST_initDevice {
|
||||
my ($hash) = @_;
|
||||
my $devName = $hash->{CCNAME};
|
||||
|
||||
BlockingCall("GOOGLECAST_findChromecasts", $hash->{NAME}, "GOOGLECAST_findChromecastsResult");
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub GOOGLECAST_findChromecastsResult {
|
||||
my ($string) = @_;
|
||||
my ($name, @ccResult) = split("\\|", $string);
|
||||
my $hash = $main::defs{$name};
|
||||
my $devName = $hash->{CCNAME};
|
||||
$hash->{helper}{ccdevice} = "";
|
||||
|
||||
for my $i (0..$#ccResult) {
|
||||
if($ccResult[$i] eq "CCDEVICE" and $ccResult[$i+5] eq $devName) {
|
||||
Log3 $hash, 4, "GOOGLECAST ($hash->{NAME}): init cast device $devName";
|
||||
eval {
|
||||
$hash->{helper}{ccdevice} = GOOGLECAST_createChromecastPython($ccResult[$i+1],$ccResult[$i+2],$ccResult[$i+3],$ccResult[$i+4],$ccResult[$i+5]);
|
||||
};
|
||||
if($@) {
|
||||
$hash->{helper}{ccdevice} = "";
|
||||
}
|
||||
Log3 $hash, 4, "GOOGLECAST ($hash->{NAME}): device initialized";
|
||||
}
|
||||
}
|
||||
|
||||
if($hash->{helper}{ccdevice} eq "") {
|
||||
Log3 $hash, 4, "GOOGLECAST: $devName not found, retry in 10s.";
|
||||
InternalTimer(gettimeofday()+10, "GOOGLECAST_initDevice", $hash, 0);
|
||||
return undef;
|
||||
}
|
||||
|
||||
Log3 $hash, 3, "GOOGLECAST: $devName initialized successfully";
|
||||
|
||||
GOOGLECAST_addSocketToMainloop($hash);
|
||||
GOOGLECAST_checkConnection($hash);
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub GOOGLECAST_Attribute($$$$) {
|
||||
my ($mode, $devName, $attrName, $attrValue) = @_;
|
||||
|
||||
if($mode eq "set") {
|
||||
|
||||
} elsif($mode eq "del") {
|
||||
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub GOOGLECAST_Set($@) {
|
||||
my ($hash, $name, @params) = @_;
|
||||
my $workType = shift(@params);
|
||||
my $list = "stop:noArg pause:noArg quitApp:noArg play playFavorite:1,2,3,4,5 volume:slider,0,1,100";
|
||||
|
||||
# check parameters for set function
|
||||
if($workType eq "?") {
|
||||
return SetExtensions($hash, $list, $name, $workType, @params);
|
||||
}
|
||||
|
||||
if($workType eq "stop") {
|
||||
GOOGLECAST_setStop($hash);
|
||||
} elsif($workType eq "pause") {
|
||||
GOOGLECAST_setPause($hash);
|
||||
} elsif($workType eq "play") {
|
||||
GOOGLECAST_setPlay($hash, $params[0]);
|
||||
} elsif($workType eq "playFavorite") {
|
||||
GOOGLECAST_setPlayFavorite($hash, $params[0]);
|
||||
} elsif($workType eq "quitApp") {
|
||||
GOOGLECAST_setQuitApp($hash);
|
||||
} elsif($workType eq "volume") {
|
||||
GOOGLECAST_setVolume($hash, $params[0]);
|
||||
} else {
|
||||
return SetExtensions($hash, $list, $name, $workType, @params);
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
### volume ###
|
||||
sub GOOGLECAST_setVolume {
|
||||
my ($hash, $volume) = @_;
|
||||
$volume = $volume/100;
|
||||
|
||||
eval {
|
||||
$hash->{helper}{ccdevice}->set_volume($volume);
|
||||
};
|
||||
}
|
||||
|
||||
### playType ###
|
||||
sub GOOGLECAST_setPlayType {
|
||||
my ($hash, $url, $mime) = @_;
|
||||
|
||||
eval {
|
||||
$hash->{helper}{ccdevice}->{media_controller}->play_media($url, $mime);
|
||||
};
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub GOOGLECAST_setPlayType_String {
|
||||
my ($string) = @_;
|
||||
my ($name, $url, $mime) = split("\\|", $string);
|
||||
my $hash = $main::defs{$name};
|
||||
|
||||
if($mime ne "" && $url ne "") {
|
||||
GOOGLECAST_setPlayType($hash, $url, $mime);
|
||||
}
|
||||
}
|
||||
|
||||
### playMedia ###
|
||||
sub GOOGLECAST_setPlayMedia {
|
||||
my ($hash, $url) = @_;
|
||||
|
||||
BlockingCall("GOOGLECAST_setPlayMediaBlocking", $hash->{NAME}."|".$url, "GOOGLECAST_setPlayType_String");
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub GOOGLECAST_setPlayMedia_String {
|
||||
my ($string) = @_;
|
||||
my ($name, $videoUrl, $origUrl) = split("\\|", $string);
|
||||
my $hash = $main::defs{$name};
|
||||
|
||||
if($videoUrl ne "") {
|
||||
GOOGLECAST_setPlayMedia($hash, $videoUrl);
|
||||
} else {
|
||||
GOOGLECAST_setPlayMedia($hash, $origUrl);
|
||||
}
|
||||
}
|
||||
|
||||
sub GOOGLECAST_setPlayMediaBlocking {
|
||||
my ($string) = @_;
|
||||
my ($name, $url) = split("\\|", $string);
|
||||
|
||||
#$url = "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
|
||||
#$url = "http://swr-mp3-m-swr3.akacast.akamaistream.net:80/7/720/137136/v1/gnl.akacast.akamaistream.net/swr-mp3-m-swr3";
|
||||
|
||||
my $ua = new LWP::UserAgent(agent => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.5) Gecko/20060719 Firefox/1.5.0.5');
|
||||
$ua->max_size(0);
|
||||
my $resp = $ua->get($url);
|
||||
my $mime = $resp->header('Content-Type');
|
||||
|
||||
if($mime eq "audio/x-mpegurl") {
|
||||
$mime = "audio/mpeg";
|
||||
$url = $resp->decoded_content;
|
||||
$url =~ s/\R//g;
|
||||
}
|
||||
|
||||
return $name."|".$url."|".$mime;
|
||||
}
|
||||
|
||||
### playYoutue ###
|
||||
sub GOOGLECAST_setPlayYtDl {
|
||||
my ($hash, $ytUrl) = @_;
|
||||
|
||||
BlockingCall("GOOGLECAST_setPlayYtDlBlocking", $hash->{NAME}."|".$ytUrl, "GOOGLECAST_setPlayMedia_String");
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub GOOGLECAST_setPlayYtDlBlocking {
|
||||
my ($string) = @_;
|
||||
my ($name, $ytUrl) = split("\\|", $string);
|
||||
my $videoUrl = "";
|
||||
|
||||
eval {
|
||||
$videoUrl = GOOGLECAST_getYTVideoURLPython($ytUrl);
|
||||
};
|
||||
|
||||
return $name."|".$videoUrl."|".$ytUrl;
|
||||
}
|
||||
|
||||
### stop ###
|
||||
sub GOOGLECAST_setStop {
|
||||
my ($hash) = @_;
|
||||
|
||||
eval {
|
||||
$hash->{helper}{ccdevice}->{media_controller}->stop();
|
||||
};
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
### playFavorite ###
|
||||
sub GOOGLECAST_setPlayFavorite {
|
||||
my ($hash, $favoriteNr) = @_;
|
||||
GOOGLECAST_setPlay($hash, AttrVal($hash->{NAME}, "favoriteURL_".$favoriteNr, ""));
|
||||
return undef;
|
||||
}
|
||||
|
||||
### play ###
|
||||
sub GOOGLECAST_setPlay {
|
||||
my ($hash, $url) = @_;
|
||||
|
||||
if(defined($url)) {
|
||||
#support streams are listed here
|
||||
#https://github.com/rg3/youtube-dl/blob/master/docs/supportedsites.md
|
||||
GOOGLECAST_setPlayYtDl($hash, $url);
|
||||
} else {
|
||||
eval {
|
||||
$hash->{helper}{ccdevice}->{media_controller}->play();
|
||||
};
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
### pause ###
|
||||
sub GOOGLECAST_setPause {
|
||||
my ($hash) = @_;
|
||||
|
||||
eval {
|
||||
$hash->{helper}{ccdevice}->{media_controller}->pause();
|
||||
};
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
### quitApp ###
|
||||
sub GOOGLECAST_setQuitApp {
|
||||
my ($hash) = @_;
|
||||
|
||||
eval {
|
||||
$hash->{helper}{ccdevice}->quit_app();
|
||||
};
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub GOOGLECAST_Undef($) {
|
||||
my ($hash) = @_;
|
||||
|
||||
#remove internal timer
|
||||
RemoveInternalTimer($hash);
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub GOOGLECAST_Get($$) {
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub GOOGLECAST_updateReading {
|
||||
my ($hash, $readingName, $value) = @_;
|
||||
my $oldValue = ReadingsVal($hash->{NAME}, $readingName, "");
|
||||
|
||||
if(!defined($value)) {
|
||||
$value = "";
|
||||
}
|
||||
|
||||
if($oldValue ne $value) {
|
||||
readingsSingleUpdate($hash, $readingName, $value, 1);
|
||||
}
|
||||
}
|
||||
|
||||
sub GOOGLECAST_newChash {
|
||||
my ($hash, $socket, $chash) = @_;
|
||||
|
||||
$chash->{TYPE} = $hash->{TYPE};
|
||||
$chash->{UDN} = -1;
|
||||
|
||||
$chash->{NR} = $devcount++;
|
||||
|
||||
$chash->{phash} = $hash;
|
||||
$chash->{PNAME} = $hash->{NAME};
|
||||
|
||||
$chash->{CD} = $socket;
|
||||
$chash->{FD} = $socket->fileno();
|
||||
|
||||
#$chash->{PORT} = $socket->sockport if( $socket->sockport );
|
||||
|
||||
$chash->{TEMPORARY} = 1;
|
||||
$attr{$chash->{NAME}}{room} = 'hidden';
|
||||
|
||||
$defs{$chash->{NAME}} = $chash;
|
||||
$selectlist{$chash->{NAME}} = $chash;
|
||||
}
|
||||
|
||||
sub GOOGLECAST_addSocketToMainloop {
|
||||
my ($hash) = @_;
|
||||
my $sock;
|
||||
|
||||
eval {
|
||||
$sock = $hash->{helper}{ccdevice}->{socket_client}->get_socket();
|
||||
};
|
||||
|
||||
my $chash = GOOGLECAST_newChash($hash, $sock, {NAME => "GOOGLECAST-".$hash->{NAME}});
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub GOOGLECAST_checkConnection {
|
||||
my ($hash) = @_;
|
||||
|
||||
eval {
|
||||
Log3 $hash, 5, "GOOGLECAST ($hash->{NAME}): run_once";
|
||||
$hash->{helper}{ccdevice}->{socket_client}->run_once();
|
||||
};
|
||||
|
||||
if($@ || !defined($selectlist{"GOOGLECAST-".$hash->{NAME}})) {
|
||||
Log3 $hash, 4, "GOOGLECAST ($hash->{NAME}): checkConnection, connection failure, reconnect...";
|
||||
GOOGLECAST_initDevice($hash);
|
||||
GOOGLECAST_updateReading($hash, "presence", "offline");
|
||||
return undef;
|
||||
}
|
||||
|
||||
InternalTimer(gettimeofday()+10, "GOOGLECAST_checkConnection", $hash, 0);
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
sub GOOGLECAST_Read {
|
||||
my ($hash) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
$hash = $hash->{phash};
|
||||
|
||||
eval {
|
||||
Log3 $hash, 5, "GOOGLECAST ($hash->{NAME}): run_once";
|
||||
$hash->{helper}{ccdevice}->{socket_client}->run_once();
|
||||
};
|
||||
|
||||
if($@) {
|
||||
Log3 $hash, 4, "GOOGLECAST ($hash->{NAME}): connection failure, reconnect...";
|
||||
eval {
|
||||
delete($selectlist{$name});
|
||||
};
|
||||
GOOGLECAST_initDevice($hash);
|
||||
GOOGLECAST_updateReading($hash, "presence", "offline");
|
||||
return undef;
|
||||
}
|
||||
|
||||
GOOGLECAST_updateReading($hash, "presence", "online");
|
||||
GOOGLECAST_updateReading($hash, "name", $hash->{helper}{ccdevice}->{name});
|
||||
GOOGLECAST_updateReading($hash, "model", $hash->{helper}{ccdevice}->{model_name});
|
||||
GOOGLECAST_updateReading($hash, "uuid", $hash->{helper}{ccdevice}->{uuid});
|
||||
GOOGLECAST_updateReading($hash, "castType", $hash->{helper}{ccdevice}->{cast_type});
|
||||
GOOGLECAST_updateReading($hash, "model", $hash->{helper}{ccdevice}->{model_name});
|
||||
GOOGLECAST_updateReading($hash, "appId", $hash->{helper}{ccdevice}->{app_id});
|
||||
GOOGLECAST_updateReading($hash, "appName", $hash->{helper}{ccdevice}->{app_display_name});
|
||||
GOOGLECAST_updateReading($hash, "idle", $hash->{helper}{ccdevice}->{is_idle});
|
||||
|
||||
my $newStatus = $hash->{helper}{ccdevice}->{media_controller}->{status};
|
||||
if(defined($newStatus)) {
|
||||
#GOOGLECAST_updateReading($hash, "mediaStatus", $newStatus);
|
||||
GOOGLECAST_updateReading($hash, "mediaTitle", $newStatus->{title});
|
||||
GOOGLECAST_updateReading($hash, "mediaSeriesTitle", $newStatus->{series_title});
|
||||
GOOGLECAST_updateReading($hash, "mediaSeason", $newStatus->{season});
|
||||
GOOGLECAST_updateReading($hash, "mediaEpisode", $newStatus->{episode});
|
||||
GOOGLECAST_updateReading($hash, "mediaArtist", $newStatus->{artist});
|
||||
GOOGLECAST_updateReading($hash, "mediaAlbum", $newStatus->{album_name});
|
||||
GOOGLECAST_updateReading($hash, "mediaAlbumArtist", $newStatus->{album_artist});
|
||||
GOOGLECAST_updateReading($hash, "mediaTrack", $newStatus->{track});
|
||||
if(length($newStatus->{images}) > 0) {
|
||||
GOOGLECAST_updateReading($hash, "mediaImage", $newStatus->{images}[0]->{url});
|
||||
} else {
|
||||
GOOGLECAST_updateReading($hash, "mediaImage", "");
|
||||
}
|
||||
}
|
||||
|
||||
my $newCastStatus = $hash->{helper}{ccdevice}->{status};
|
||||
if(defined($newCastStatus)) {
|
||||
#GOOGLECAST_updateReading($hash, "castStatus", $newCastStatus);
|
||||
GOOGLECAST_updateReading($hash, "volume", $newCastStatus->{volume_level}*100);
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
use Inline Python => <<'PYTHON_CODE_END';
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import pychromecast
|
||||
import time
|
||||
import logging
|
||||
import youtube_dl
|
||||
|
||||
def GOOGLECAST_findChromecastsPython():
|
||||
logging.basicConfig(level=logging.CRITICAL)
|
||||
return pychromecast.discovery.discover_chromecasts()
|
||||
|
||||
def GOOGLECAST_createChromecastPython(ip, port, uuid, model_name, friendly_name):
|
||||
logging.basicConfig(level=logging.CRITICAL)
|
||||
return pychromecast._get_chromecast_from_host((ip, int(port), uuid, model_name, friendly_name), blocking=False, timeout=0.1, tries=1, retry_wait=0.1)
|
||||
|
||||
def GOOGLECAST_getYTVideoURLPython(yt_url):
|
||||
ydl = youtube_dl.YoutubeDL({'quiet': '1', 'no_warnings': '1'})
|
||||
|
||||
with ydl:
|
||||
result = ydl.extract_info(
|
||||
yt_url,
|
||||
download=False # We just want to extract the info
|
||||
)
|
||||
|
||||
if 'entries' in result:
|
||||
# Can be a playlist or a list of videos
|
||||
video = result['entries'][0]
|
||||
else:
|
||||
# Just a video
|
||||
video = result
|
||||
|
||||
video_url = video['url']
|
||||
return video_url
|
||||
|
||||
PYTHON_CODE_END
|
||||
|
||||
1;
|
||||
|
||||
|
||||
=pod
|
||||
=item device
|
||||
=item summary Easily control your Google Cast devices (Video, Audio, Google Home)
|
||||
=item summary_DE Einfache Steuerung deiner Google Cast Geräte (Video, Audio, Google Home)
|
||||
=begin html
|
||||
|
||||
<a name="GOOGLECAST"></a>
|
||||
<h3>GOOGLECAST</h3>
|
||||
<ul>
|
||||
GOOGLECAST is used to control your Google Cast device<br><br>
|
||||
<b>Note</b><br>Following packages are required:
|
||||
<ul>
|
||||
<li>sudo apt-get install libwww-perl python-enum34 python-dev libextutils-makemaker-cpanfile-perl python-pip cpanminus</li>
|
||||
<li>sudo pip install netifaces</li>
|
||||
<li>sudo pip install enum34</li>
|
||||
<li>sudo pip install pychromecast</li>
|
||||
<li>sudo pip install youtube-dl</li>
|
||||
<li>sudo cpanm Inline::Python</li>
|
||||
</ul>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<a name="GOOGLECASTdefine" id="GOOGLECASTdefine"></a>
|
||||
<b>Define</b>
|
||||
<ul>
|
||||
<code>define <name> GOOGLECAST <name></code><br>
|
||||
<br>
|
||||
Example:
|
||||
<ul>
|
||||
<code>define livingroom.chromecast GOOGLECAST livingroom</code><br><br>
|
||||
Wait a few seconds till presence switches to online...<br><br>
|
||||
<code>set livingroom.chromecast play https://www.youtube.com/watch?v=YE7VzlLtp-4</code><br>
|
||||
</ul>
|
||||
<br>
|
||||
Following media types are supported:<br>
|
||||
<a href="https://developers.google.com/cast/docs/media">Supported media formats</a><br>
|
||||
Play with youtube-dl works for following URLs:<br>
|
||||
<a href="https://rg3.github.io/youtube-dl/supportedsites.html">Supported youtube-dl sites</a><br>
|
||||
<br>
|
||||
</ul>
|
||||
|
||||
<br>
|
||||
|
||||
<a name="GOOGLECASTset" id="GOOGLECASTset"></a>
|
||||
<b>Set</b>
|
||||
<ul>
|
||||
<code>set <name> <command> [<parameter>]</code><br>
|
||||
The following commands are defined:<br><br>
|
||||
<ul>
|
||||
<li><code><b>play</b> URL</code> - play from URL</li>
|
||||
<li><code><b>play</b></code> - play, like resume if paused previsously</li>
|
||||
<li><code><b>playFavorite</b></code> - plays URL from favoriteURL_[1-5]</li>
|
||||
<li><code><b>stop</b></code> - stop, stops current playback</li>
|
||||
<li><code><b>pause</b></code> - pause</li>
|
||||
<li><code><b>quitApp</b></code> - quit current application, like YouTube</li>
|
||||
</ul>
|
||||
<br>
|
||||
</ul>
|
||||
|
||||
<a name="GOOGLECASTattr" id="GOOGLECASTattr"></a>
|
||||
<b>Attributes</b>
|
||||
<ul>
|
||||
<li><code><b>favoriteURL_[1-5]</b></code> - save URL to play afterwards with playFavorite [1-5]</li>
|
||||
</ul>
|
||||
<br>
|
||||
|
||||
<a name="GOOGLECASTget" id="GOOGLECASTget"></a>
|
||||
<b>Get</b>
|
||||
<ul>
|
||||
<code>n/a</code>
|
||||
</ul>
|
||||
<br>
|
||||
|
||||
</ul>
|
||||
|
||||
=end html
|
||||
=cut
|
||||
|
@ -428,6 +428,7 @@ FHEM/98_expandJSON.pm dev0 http://forum.fhem.de Unterstue
|
||||
FHEM/98_fheminfo.pm betateilchen http://forum.fhem.de Sonstiges
|
||||
FHEM/98_fhemdebug.pm rudolfkoenig http://forum.fhem.de Sonstiges
|
||||
FHEM/98_GoogleAuth.pm betateilchen http://forum.fhem.de Unterstuetzende Dienste
|
||||
FHEM/98_GOOGLECAST.pm dominikkarall http://forum.fhem.de Multimedia
|
||||
FHEM/98_help.pm betateilchen http://forum.fhem.de Sonstiges
|
||||
FHEM/98_HourCounter.pm john http://forum.fhem.de MAX
|
||||
FHEM/98_logProxy.pm justme1968 http://forum.fhem.de Frontends/SVG Plots logProxy
|
||||
|
Loading…
Reference in New Issue
Block a user