2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-15 16:19:11 +00:00

37_echodevice.pm: bugfixing voice_reading

git-svn-id: https://svn.fhem.de/fhem/trunk@28095 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
michael.winkler 2023-10-27 12:58:08 +00:00
parent af19023257
commit 91d73e37b4

View File

@ -2,6 +2,15 @@
#
##############################################
#
# 2023.10.27 v0.2.22
# - CHANGE: voice_reading auf neue API umgestellt
# - FEATURE voice_person (Zeigt wer das letzte Voice Command gesagt hat, wenn eingerichtet)
#
# 2023.01.19 v0.2.21
# - BUG: Refresh Token
# Attribut "fhem_home"
# - FEATURE Neues Reading "parse_error"
#
# 2022.11.22 v0.2.20
# - FEATURE: Unterstützung A4ZXE0RM7LQ7A Echo Dot Gen5
#
@ -498,7 +507,7 @@ use lib ('./FHEM/lib', './lib');
use MP3::Info;
use MIME::Base64;
my $ModulVersion = "0.2.19";
my $ModulVersion = "0.2.22";
my $AWSPythonVersion = "0.0.3";
my $NPMLoginTyp = "unbekannt";
my $QueueNumber = 0;
@ -671,7 +680,7 @@ sub echodevice_Get($@) {
$usage .= "help:noArg " ;
}
elsif ($hash->{model} eq "ACCOUNT") {
$usage .= "settings:noArg devices:noArg actions:noArg tracks:noArg help:noArg conversations:noArg html_results:noArg address status:noArg customer-history-records:noArg";
$usage .= "settings:noArg devices:noArg actions:noArg tracks:noArg help:noArg conversations:noArg html_results:noArg address status:noArg customer-history-records:noArg NPM_check:noArg";
}
else {
$usage .= "tunein settings:noArg primeplayeigene_albums primeplayeigene_tracks primeplayeigene_artists primeplayeigeneplaylist:noArg help:noArg html_results:noArg ";
@ -818,6 +827,13 @@ sub echodevice_Get($@) {
}
if ($command eq "NPM_check") {
$return = echodevice_NPMCheck($hash);
return $return;
}
if ($ConnectState ne "connected") {
return "$name is not connected. Aborting...";
}
@ -893,7 +909,7 @@ sub echodevice_Set($@) {
$usage .= 'AWS_Access_Key AWS_Secret_Key TTS_IPAddress TTS_Filename TTS_TuneIn POM_TuneIn POM_IPAddress POM_Filename AWS_OutputFormat:mp3,ogg_vorbis,pcm textmessage ';# if(defined($hash->{helper}{".COMMSID"}));
$usage .= 'config_address_from config_address_to config_address_between mobilmessage ';
$usage .= 'login:noArg loginwithcaptcha login2FACode ' if($hash->{LOGINMODE} eq "NORMAL");
$usage .= 'NPM_install:noArg NPM_login:new,refresh ' if($hash->{LOGINMODE} eq "NPM");
$usage .= 'NPM_install:noArg NPM_login:new,refresh NPM_check:noArg' if($hash->{LOGINMODE} eq "NPM");
# Einkaufsliste
my $ShoppingListe = ReadingsVal($name, "list_SHOPPING_ITEM", "");
@ -906,7 +922,7 @@ sub echodevice_Set($@) {
elsif ($hash->{model} eq "Echo Multiroom" || $hash->{model} eq "Sonos Display" || $hash->{model} eq "Echo Stereopaar") {
$usage .= 'volume:slider,0,1,100 play:noArg pause:noArg next:noArg previous:noArg forward:noArg rewind:noArg shuffle:on,off repeat:on,off ';
$usage .= 'tunein primeplaylist primeplaysender primeplayeigene primeplayeigeneplaylist tts tts_translate:textField-long playownmusic:textField-long saveownplaylist:textField-long ';
$usage .= 'tunein primeplaylist primeplaysender primeplayeigene primeplayeigeneplaylist tts tts_translate:textField-long playownmusic:textField-long saveownplaylist:textField-long speak speak_ssml ';
if(defined($tracks)) {
$tracks =~ s/ /_/g;
@ -1730,8 +1746,16 @@ sub echodevice_SendCommand($$$) {
elsif ($type eq "alarmvolume") {
$SendUrl .= "/api/device-notification-state?_=".int(time);
}
elsif ($type eq "activities") {
$SendUrl = "https://www.amazon.de/alexa-privacy/apd/rvh/customer-history-records/?startTime=0&endTime=2005090388459&recordType=VOICE_HISTORY&maxRecordSize=100";
$SendMetode = "GET";
$SendDataL = "" ;
$SendData = "";
}
elsif ($type eq "activities1") {
if (int(AttrVal($name,"intervalvoice",999999)) != 999999) {
$SendUrl .= "/api/activities?startTime=&size=10&offset=1&_=".int(time);
}
@ -2109,10 +2133,12 @@ sub echodevice_SendCommand($$$) {
my $SpeakVolume;
$SpeakVolume = int(AttrVal($hash->{IODev}{NAME},"speak_volume",0));
$SpeakVolume = int(AttrVal($name,"speak_volume",0)) if($SpeakVolume == 0);
if($SpeakVolume > 0){
#if(ReadingsVal($name , "volume", 50) < ReadingsVal($name , "volume_alarm", 50)) {
$SendData = '{"behaviorId":"PREVIEW","sequenceJson":"{\"@type\":\"com.amazon.alexa.behaviors.model.Sequence\",\"startNode\":{\"@type\":\"com.amazon.alexa.behaviors.model.SerialNode\",\"nodesToExecute\":[{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"Alexa.DeviceControls.Volume\",\"operationPayload\":{\"deviceSerialNumber\":\"' . $hash->{helper}{".SERIAL"} . '\",\"customerId\":\"' . $hash->{IODev}->{helper}{".CUSTOMER"} .'\",\"locale\":\"de-DE\",\"value\":\"'.$SpeakVolume.'\",\"deviceType\":\"' . $hash->{helper}{DEVICETYPE} . '\"}},{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"Alexa.Speak\",\"operationPayload\":{\"locale\":\"de-DE\",\"deviceSerialNumber\":\"' . $hash->{helper}{".SERIAL"} . '\",\"customerId\":\"' . $hash->{IODev}->{helper}{".CUSTOMER"} .'\",\"deviceType\":\"' . $hash->{helper}{DEVICETYPE} . '\",\"textToSpeak\":\"'.$SendData.'\"}},{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"Alexa.DeviceControls.Volume\",\"operationPayload\":{\"deviceSerialNumber\":\"' . $hash->{helper}{".SERIAL"} . '\",\"customerId\":\"' . $hash->{IODev}->{helper}{".CUSTOMER"} .'\",\"locale\":\"de-DE\",\"value\":\"'.ReadingsVal($name , "volume", 50).'\",\"deviceType\":\"' . $hash->{helper}{DEVICETYPE} . '\"}}]}}","status":"ENABLED"}'
Log3 $name, 3, "[$name] [SpeakVolume] send...";
$SendData = '{"behaviorId":"PREVIEW","sequenceJson":"{\"@type\":\"com.amazon.alexa.behaviors.model.Sequence\",\"startNode\":{\"@type\":\"com.amazon.alexa.behaviors.model.SerialNode\",\"nodesToExecute\":[{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"Alexa.DeviceControls.Volume\",\"operationPayload\":{\"deviceSerialNumber\":\"' . $hash->{helper}{".SERIAL"} . '\",\"customerId\":\"' . $hash->{IODev}->{helper}{".CUSTOMER"} .'\",\"locale\":\"de-DE\",\"value\":\"'.$SpeakVolume.'\",\"deviceType\":\"' . $hash->{helper}{DEVICETYPE} . '\"}},{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"Alexa.Speak\",\"operationPayload\":{\"locale\":\"de-DE\",\"deviceSerialNumber\":\"' . $hash->{helper}{".SERIAL"} . '\",\"customerId\":\"' . $hash->{IODev}->{helper}{".CUSTOMER"} .'\",\"deviceType\":\"' . $hash->{helper}{DEVICETYPE} . '\",\"textToSpeak\":\"'.$SendData.'\"}},{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"Alexa.DeviceControls.Volume\",\"operationPayload\":{\"deviceSerialNumber\":\"' . $hash->{helper}{".SERIAL"} . '\",\"customerId\":\"' . $hash->{IODev}->{helper}{".CUSTOMER"} .'\",\"locale\":\"de-DE\",\"value\":\"'.ReadingsVal($name , "volume", 50).'\",\"deviceType\":\"' . $hash->{helper}{DEVICETYPE} . '\"}}]}}","status":"ENABLED"}';
Log3 $name, 3, "[$name] [SpeakVolume] send... $SendData";
}
else {
$SendData = echodevice_getsequenceJson($hash,$type,$SendData);
@ -2213,7 +2239,7 @@ sub echodevice_SendCommand($$$) {
sub echodevice_HandleCmdQueue($) {
my ($hash, $param) = @_;
my $name = $hash->{NAME};
return undef if(!defined($hash->{helper}{CMD_QUEUE}));
$hash->{helper}{RUNNING_REQUEST} = 0 if(!defined($hash->{helper}{RUNNING_REQUEST}));
@ -2237,7 +2263,7 @@ sub echodevice_HandleCmdQueue($) {
# if($hash->{model} eq "ACCOUNT") {$AmazonHeader = "Cookie: ".$hash->{helper}{".COOKIE"}."\r\ncsrf: ".$hash->{helper}{".CSRF"}."\r\nContent-Type: application/json; charset=UTF-8";}
# else {$AmazonHeader = "Cookie: ".$hash->{IODev}->{helper}{".COOKIE"}."\r\ncsrf: ".$hash->{IODev}->{helper}{".CSRF"}."\r\nContent-Type: application/json; charset=UTF-8";}
if($hash->{model} eq "ACCOUNT") {$AmazonHeader = "User-Agent: ". $UserAgent ."\r\nAccept-Language: " . $HeaderLanguage . "\r\nDNT: 1\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\nCookie:".$hash->{helper}{".COOKIE"}."\r\ncsrf: ".$hash->{helper}{".CSRF"}."\r\nContent-Type: application/json; charset=UTF-8";}
else {$AmazonHeader = "User-Agent: ". $UserAgent ."\r\nAccept-Language: " . $HeaderLanguage . "\r\nDNT: 1\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\nCookie:".$hash->{IODev}->{helper}{".COOKIE"}."\r\ncsrf: ".$hash->{IODev}->{helper}{".CSRF"}."\r\nContent-Type: application/json; charset=UTF-8";}
@ -2488,6 +2514,15 @@ sub echodevice_Parse($$$) {
Log3 $name, 4, "[$name] [echodevice_Parse] [$msgtype] [$msgnumber] DATA Dumper=" . Dumper(echodevice_anonymize($hash, $data));
}
# Rate exceeded: Too many requests https://forum.fhem.de/index.php/topic,82631.msg1251020.html#msg1251020
if (Dumper(echodevice_anonymize($hash, $data)) =~ m/Too many requests/ ) {
readingsSingleUpdate ($hash, "parse_error", "Too many requests" ,0);
Log3 $name, 3, "[$name] [echodevice_Parse] [$msgtype] [$msgnumber] Too many requests" ;
}
else {
readingsSingleUpdate ($hash, "parse_error", "OK" ,0);
}
# Nächsten Auftrag starten
echodevice_HandleCmdQueue($hash);
@ -2782,8 +2817,79 @@ sub echodevice_Parse($$$) {
if (index($data, '{') == -1) {$data = '{"data": "nodata"}';}
my $json = eval { JSON->new->utf8(0)->decode($data) };
my $Person ;
if($msgtype eq "activities") {
if (ref($json) eq "HASH") {
if(defined($json->{customerHistoryRecords}) && ref($json->{customerHistoryRecords}) eq "ARRAY") {
foreach my $recordKey (@{$json->{customerHistoryRecords}}) {
my @recordKeys = split("#",$recordKey->{recordKey});
$sourceDeviceIds = @recordKeys[3];
$Person = 0;
if ($recordKey->{utteranceType} ne "WAKE_WORD_ONLY" and $recordKey->{utteranceType} ne "DEVICE_ARBITRATION") {
if(defined($modules{$hash->{TYPE}}{defptr}{$sourceDeviceIds})) {
my $echohash = $modules{$hash->{TYPE}}{defptr}{$sourceDeviceIds};
my $timestamp = int(ReadingsVal($echohash->{NAME},'voice_timestamp',9999));
if($timestamp >= int($recordKey->{voiceHistoryRecordItems}[0]{timestamp})) {
if ($recordKey->{voiceHistoryRecordItems}[0]{personsInfo}[0]{personFirstName} ne ReadingsVal($echohash->{NAME},'voice_person',"unbekannt") and $recordKey->{voiceHistoryRecordItems}[0]{personsInfo}[0]{personFirstName} ne "") {
$Person = 1;
}
else {
next;
}
}
$echohash->{".updateTimestamp"} = FmtDateTime(int($card->{creationTimestamp}/1000));
readingsBeginUpdate($echohash);
if ($Person eq 1) {
readingsBulkUpdate($echohash, "voice_person", $recordKey->{voiceHistoryRecordItems}[0]{personsInfo}[0]{personFirstName}, 1);
}
else {
if ($recordKey->{voiceHistoryRecordItems}[0]{personsInfo}[0]{personFirstName} ne "") {
readingsBulkUpdate($echohash, "voice_person", $recordKey->{voiceHistoryRecordItems}[0]{personsInfo}[0]{personFirstName}, 1);
}
readingsBulkUpdate($echohash, "voice_timestamp", $recordKey->{voiceHistoryRecordItems}[0]{timestamp}, 1);
readingsBulkUpdate($echohash, "voice", $recordKey->{voiceHistoryRecordItems}[0]{transcriptText}, 1);
}
readingsEndUpdate($echohash,1);
$echohash->{CHANGETIME}[0] = FmtDateTime(int($card->{creationTimestamp}/1000));
}
#Log3 $name, 3, "[$name] [echodevice_Parse] [" . $echohash->{NAME} . "] Alexatext = ".$sourceDeviceIds . " transcriptText=" . $recordKey->{voiceHistoryRecordItems}[0]{transcriptText} ." Person=" . $recordKey->{voiceHistoryRecordItems}[0]{personsInfo}[0]{personFirstName};
}
}
}
# Timer für Realtime Check!
my $IntervalVoice = int(AttrVal($name,"intervalvoice",999999));
if ($IntervalVoice != 999999 && $hash->{STATE} eq "connected" && AttrVal($name,"disable",0) == 0) {
Log3 $name, 5, "[$name] [echodevice_Parse] [$msgtype] [$msgnumber] refresh voice command IntervalVoice=$IntervalVoice ";
$hash->{helper}{echodevice_refreshvoice} = 1;
$hash->{helper}{echodevice_refreshvoice_lastdate} = time();
RemoveInternalTimer($hash, "echodevice_refreshvoice");
InternalTimer(gettimeofday() + $IntervalVoice , "echodevice_refreshvoice", $hash, 0);
}
else {
$hash->{helper}{echodevice_refreshvoice} = 0;
}
}
else {
Log3 $name, 3, "[$name] [echodevice_Parse] [$msgtype] [$msgnumber] WRONG JSON Type Type=" . ref($json);
}
}
if($msgtype eq "activities2") {
if (ref($json) eq "HASH") {
if(defined($json->{activities}) && ref($json->{activities}) eq "ARRAY") {
foreach my $card (@{$json->{activities}}) {
@ -3665,7 +3771,7 @@ sub echodevice_Parse($$$) {
readingsBulkUpdate($devicehash, "presence", ($device->{online}?"present":"absent"), 1);
#readingsBulkUpdate($devicehash, "state", "absent", 1) if(!$device->{online});
readingsBulkUpdate($devicehash, "version", $device->{softwareVersion}, 1);
readingsEndUpdate($devicehash,1);
$devicehash->{helper}{".SERIAL"} = $device->{serialNumber};
$devicehash->{helper}{DEVICETYPE} = $device->{deviceType};
$devicehash->{helper}{NAME} = $device->{accountName};
@ -3673,6 +3779,19 @@ sub echodevice_Parse($$$) {
$devicehash->{helper}{VERSION} = $device->{softwareVersion};
$devicehash->{helper}{".CUSTOMER"} = $device->{deviceOwnerCustomerId};
# Multiroom
if ($device->{deviceType} eq "A3C9PE6TNYLTCH") {
Log3 $name, 4, "[echodevice_GetSettings] Multiroom Device erkannt" ;
my $EchoMembers = "";
foreach my $clusterMember (@{$device->{clusterMembers}}) {
if ($EchoMembers eq "") {$EchoMembers = $clusterMember;} else {$EchoMembers = $EchoMembers . "," . $clusterMember;}
}
Log3 $name, 4, "[echodevice_GetSettings] Multiroom Devices $EchoMembers" ;
readingsBulkUpdate($devicehash, "clusterMembers", $EchoMembers, 1);
}
readingsEndUpdate($devicehash,1);
if ($device->{deviceFamily} eq "ECHO" || $device->{deviceFamily} eq "KNIGHT") {
Log3 $name, 4, "[echodevice_GetSettings] SET 5 DEF=" . $devicehash->{DEF} . " TYPE=".$device->{deviceType}. 'SN Hash=' . $devicehash->{helper}{".SERIAL"} . ' SN Result=' . $device->{serialNumber} ;
$hash->{helper}{".SERIAL"} = $device->{serialNumber};
@ -4787,7 +4906,7 @@ sub echodevice_NPMLoginNew($){
} while ($NodeLoop eq "1");
# Prüfen ob das alexa-cookie Mdoul vorhanden ist
if (!(-e "cache/alexa-cookie/node_modules/alexa-cookie2/alexa-cookie.js")) {
if (!(-e $npm_fhem_home . "/cache/alexa-cookie/node_modules/alexa-cookie2/alexa-cookie.js")) {
$InstallResult .= '<p>Das alexa-cookie Modul wurde nicht gefunden. Bitte fuehrt am Amazon Account Device einen set "<strong>NPM_install</strong>" durch </p>';
$InstallResult .= '<br><form><input type="button" value="Zur&uuml;ck" onClick="history.go(-1);return true;"></form>';
$InstallResult .= "</html>";
@ -4797,7 +4916,7 @@ sub echodevice_NPMLoginNew($){
}
# Version prüfen;
echodevice_NPMCheckVersion($hash,"cache/alexa-cookie/node_modules/alexa-cookie2/package.json","echodevice_NPMLoginNew");
echodevice_NPMCheckVersion($hash, $npm_fhem_home . "/cache/alexa-cookie/node_modules/alexa-cookie2/package.json","echodevice_NPMLoginNew");
my $ProxyPort = AttrVal($name,"npm_proxy_port","3002");
my $OwnIP = "127.0.0.1";
@ -5015,7 +5134,7 @@ sub echodevice_NPMLoginRefresh($){
# Prüfen ob das alexa-cookie Mdoul vorhanden ist
Log3 $name, 4, "[$name] [echodevice_NPMLoginRefresh] check alexa-cookie.js" ;
if (!(-e "cache/alexa-cookie/node_modules/alexa-cookie2/alexa-cookie.js")) {
if (!(-e $npm_fhem_home . "/cache/alexa-cookie/node_modules/alexa-cookie2/alexa-cookie.js")) {
$InstallResult .= '<p>Das alexa-cookie Modul wurde nicht gefunden. Bitte fuehrt am Amazon Account Device einen set "<strong>NPM_install</strong>" durch </p>';
$InstallResult .= '<br><form><input type="button" value="Zur&uuml;ck" onClick="history.go(-1);return true;"></form>';
$InstallResult .= "</html>";
@ -5025,7 +5144,7 @@ sub echodevice_NPMLoginRefresh($){
}
# Version prüfen;
echodevice_NPMCheckVersion($hash,"cache/alexa-cookie/node_modules/alexa-cookie2/package.json","echodevice_NPMLoginRefresh");
echodevice_NPMCheckVersion($hash,$npm_fhem_home . "/cache/alexa-cookie/node_modules/alexa-cookie2/package.json","echodevice_NPMLoginRefresh");
# Prüfen ob das Refresh Cookie gültig ist!
Log3 $name, 4, "[$name] [echodevice_NPMLoginRefresh] check Refresh Cookie String" ;
@ -5099,10 +5218,10 @@ sub echodevice_NPMWaitForCookie($){
my $CookieResult;
if ($NPMLoginTyp =~ m/Refresh/) {
$ExistSkript = $number . "refresh-cookie.js = true" if (-e $npm_fhem_home . "cache/alexa-cookie/" . $number . "refresh-cookie.js");
$ExistSkript = $number . "refresh-cookie.js = true" if (-e $npm_fhem_home . "/cache/alexa-cookie/" . $number . "refresh-cookie.js");
}
else {
$ExistSkript = $number . "create-cookie.js = true" if (-e $npm_fhem_home . "cache/alexa-cookie/" . $number . "create-cookie.js");
$ExistSkript = $number . "create-cookie.js = true" if (-e $npm_fhem_home . "/cache/alexa-cookie/" . $number . "create-cookie.js");
}
if (-e $filename) {
@ -5165,6 +5284,35 @@ sub echodevice_NPMCheckVersion ($$$) {
return $Modulversion;
}
sub echodevice_NPMCheck($) {
my ($hash) = @_;
my $name = $hash->{NAME};
# Attribute auslesen
my $npm_fhem_home = AttrVal($name,"fhem_home","/opt/fhem");
# Cache Verzeichnis prüfen
my $InstallResult = '<html><p><strong>ERGEBNIS ls -l ' . $npm_fhem_home .'/cache</strong></p><br>';
open CMD,'-|','ls -l ' . $npm_fhem_home . '/cache' or die $@;
my $line;
while (defined($line=<CMD>)) {$InstallResult .= $line. "<br>";}
close CMD;
# alexa-cookie Verzeichnis prüfen
$InstallResult .= '<html><p><strong>ERGEBNIS ls -l ' . $npm_fhem_home .'/cache/alexa-cookie</strong></p><br>';
open CMD,'-|','ls -l ' . $npm_fhem_home . '/cache/alexa-cookie' or die $@;
my $line;
while (defined($line=<CMD>)) {$InstallResult .= $line. "<br>";}
close CMD;
# Zurückbutton
$InstallResult .= "</html>";
$InstallResult =~ s/'/&#x0027/g;
return $InstallResult;
}
##########################
# TTS/POM
##########################