Umlaute in JSON

Begonnen von igami, 27 September 2017, 10:21:40

Vorheriges Thema - Nächstes Thema

igami

Ich arbeite zur Zeit an einem msgDialog modul mit dem sich ein chatBot erstellen lässt. Dabei habe ich jedoch ein Problem mit umlauten. Wenn diese in meiner Nachricht angegeben werden bekomme ich nach einiger Zeit folgende Fehlermeldung im Log:

2017.09.27 10:10:02 3: msg MichaelP: ID=1234567890.24533.1 TYPE=push ROUTE=myTelegramBot STATUS=OK PRIORITY=0 TITLE='' MSG='Ich kann folgendes für dich tun'
2017.09.27 10:10:10 3: TelegramBot_Callback myTelegramBot: resulted in NonBlockingGet timed out on read from <hidden> after 30s from SendIt
2017.09.27 10:10:10 3: TelegramBot_Callback myTelegramBot: Reached max retries (ret: NonBlockingGet timed out on read from <hidden> after 30s) for msg 50673063 : Ich kann folgendes für dich tun

Der Dialog ist als json aufgebaut:

{ "inceptum": {
    "match": "\/?(start|inceptum)",
    "message": [
      "Ich kann folgendes für dich tun:"
    ]
  },
  "abbrechen": {
    "commands":"deletereading TYPE=msgDialog %recipient%_history",
    "message": [
      "Dialog abgebrochen.",
      "",
      "/inceptum"
    ]   
  },
  "beenden": {
    "commands": "deletereading TYPE=msgDialog %recipient%_history",
    "message": [
      "Dialog beendet.",
      "",
      "/inceptum"
    ]
  }
}


Auswerten tue ich das mit

  my $dialog = encode('UTF-8', $hash->{DEF});
  $dialog = eval{decode_json($dialog)};


Wenn ich keine Umlaute angebe funktioniert es bisher wie gewollt. Kann mir jemand auf die Sprünge helfen wie ich das beheben kann?

Grüße,
igami
Pi3 mit fhem.cfg + DbLog/logProxy
Komm vorbei zum FHEM Treffen im Kreis Gütersloh! Das nächste Mal im April 2020.

MAINTAINER: archetype, LuftdatenInfo, monitoring, msgDialog, Nmap, powerMap
ToDo: AVScene, FluxLED

rudolfkoenig

Eigentlich sollte alles intern in FHEM in UTF-8 sein, auch alle gespeicherten Dateien und die Kommunikation mit der Aussenwelt (telnet/FHEMWEB) sollte diese Kodierung verwenden. Auf dem ersten Blick und ohne den Rest zu kennen sollte encode nicht notwendig sein.

igami

Wenn ich das encode weg lasse bekomme ich statt dem Umlaut im Log ein �.
Eingegeben wird alles über das DEF Feld in der Detailansicht.

Im Modul verwende ich

fhem("msg push \@$device $message");


Wenn ich eine Nachricht direkt in der Kommandozeile veranlasse kommt diese auch wie gewollt an:

msg push @MichaelP Ich kann folgendes für dich tun
oder
{fhem("msg push \@MichaelP Ich kann folgendes für dich tun")};


Momentan bin ich etwas ratlos warum es nicht funktioniert.
Pi3 mit fhem.cfg + DbLog/logProxy
Komm vorbei zum FHEM Treffen im Kreis Gütersloh! Das nächste Mal im April 2020.

MAINTAINER: archetype, LuftdatenInfo, monitoring, msgDialog, Nmap, powerMap
ToDo: AVScene, FluxLED

viegener

Ich habe endlose Stunden in die verquere Art investiert, in der perl mit unicode-Strings umgeht und kann das leider auch nicht komplett aufklären, aber folgende Informationen zu dem was passiert:

Wenn der entsprechende Fehler (resulted in NonBlockingGet timed out on read) bei telegram zurückkommt ist folgendes Problem aufgetreten:
1) Es handelt sich um einen String mit Zeichen, die nicht in einem Byte dargestellt werden können (utf-8)
2) perl markiert die Stringvariable intern als unicode-String
3) eine length operation auf dem String liefert nicht die Anzahl Bytes zurück sondern die Anzahl Zeichen (also weniger als Bytes)
4) in httputils wird beim Versenden die Content-length mit dieser inkorrekten Anzahl Bytes gesendet
5) Es kommt keine Antwort von telegram zurück

Leider unterscheiden sich auch perl-Versionen hier in der Behandlung und es gab Schwierigkeiten, die bei manchen Installationen auftraten und bei anderen nicht, ohne, dass ich die Details rausgefunden habe.

Einen Versuch wert kann es sein einen String per utf8::downgrade( zu behandeln
Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

igami

Siehe da, mit

attr myTelegramBot utf8Special 1

funktioniert es.
Vielen Dank für die, soweit wie mögliche, Aufklärung.
Pi3 mit fhem.cfg + DbLog/logProxy
Komm vorbei zum FHEM Treffen im Kreis Gütersloh! Das nächste Mal im April 2020.

MAINTAINER: archetype, LuftdatenInfo, monitoring, msgDialog, Nmap, powerMap
ToDo: AVScene, FluxLED

viegener

Ja das wollte ich noch erwähnen, ich habe utf8Special genau für diese "unerklärlichen" Fälle hinzugefügt
Schön, dass das klappt
Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

igami

Ich habe nun mal

  $dialog = eval{decode_json($dialog)};

durch
[/code]
  $dialog = eval{JSON->new->decode($dialog)};
[/code]
ersetzt.
"decode_json" ist eigentlich die Abkürzung für "JSON->new->utf8->decode". Ich habe also bewusst auf das UTF8 verzichtet, da es hierbei zu Probelemen kommt.

Das führt leider immer noch nicht dazu, dass ich auf das utf8Special verzichten kann, aber an der Stelle

  Debug("message: $message");
  $dialog = eval{JSON->new->encode($dialog)};
  $dialog =~ s/\$message/$message/g;
  Debug("dialog: $dialog");
  $dialog = eval{JSON->new->decode($dialog)};

hat es sonst dazu geführt, dass aus "Spülmittel" "Sp�lmittel" wurde.
Pi3 mit fhem.cfg + DbLog/logProxy
Komm vorbei zum FHEM Treffen im Kreis Gütersloh! Das nächste Mal im April 2020.

MAINTAINER: archetype, LuftdatenInfo, monitoring, msgDialog, Nmap, powerMap
ToDo: AVScene, FluxLED

viegener

Versuch doch mal folgendes (vor decode-json):

utf8::downgrade($dialog) if ( utf8::is_utf8($dialog)  ); 


Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

igami

Zitat von: viegener am 29 September 2017, 12:24:39
Versuch doch mal folgendes (vor decode-json):

utf8::downgrade($dialog) if ( utf8::is_utf8($dialog)  ); 


Ich habe erstmal

  Debug("message is utf8") if(utf8::is_utf8($message));

  Debug("dialog is utf8") if(utf8::is_utf8($dialog));

eingebaut und stelle fest, ist kein utf8. Bleibt nur die Frage was es dann ist und wie bekomme ich heraus, was es ist?

Modul im Anhang.
Pi3 mit fhem.cfg + DbLog/logProxy
Komm vorbei zum FHEM Treffen im Kreis Gütersloh! Das nächste Mal im April 2020.

MAINTAINER: archetype, LuftdatenInfo, monitoring, msgDialog, Nmap, powerMap
ToDo: AVScene, FluxLED

viegener

Wenn aber utf8special in telegram hilft, dann wird doch irgendwo utf8 daraus (denn das schlägt auch nur zu, wenn is_utf8 gilt). Also wird irgendwo später aus message doch noch utf8

Habe gerade in telegramBot nochmal geschaut, es sieht aber nicht so aus, als ob da etwas beteiligt wäre, was unabsichtlich is_utf8 setzen könnte.

Kann das flag nachher noch hinzukommen?

Hast Du ein use utf8 in Deinem Modul?



Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

igami

Zitat von: viegener am 29 September 2017, 13:13:30
Wenn aber utf8special in telegram hilft, dann wird doch irgendwo utf8 daraus (denn das schlägt auch nur zu, wenn is_utf8 gilt). Also wird irgendwo später aus message doch noch utf8

Habe gerade in telegramBot nochmal geschaut, es sieht aber nicht so aus, als ob da etwas beteiligt wäre, was unabsichtlich is_utf8 setzen könnte.

Kann das flag nachher noch hinzukommen?
Die Nachricht wird über den msg Befehl abgesetzt und in dem Modul gibt es die Zeile 272

            eval '$o = decode_json( Encode::encode_utf8($1) ); 1';

In meinem Modul mache ich kein utf8 draus.

Zitat von: viegener am 29 September 2017, 13:13:30
Hast Du ein use utf8 in Deinem Modul?
Ja, ist drin.
Pi3 mit fhem.cfg + DbLog/logProxy
Komm vorbei zum FHEM Treffen im Kreis Gütersloh! Das nächste Mal im April 2020.

MAINTAINER: archetype, LuftdatenInfo, monitoring, msgDialog, Nmap, powerMap
ToDo: AVScene, FluxLED

herrmannj

leider not so easy ...

utf8 kann ein bytestream (1-x mal 8 bit pro Zeichen) sein oder ein charstream (1 Zeichen darf > 8 bit sein).

Perl unterscheidet das nicht (so einfach).
is_utf8 gibt nur ein internes Flag zurück - unabhängig vom tatsächlichen Inhalt der Struktur.

Das, und verschiedene JSON und perl Versionen, ergibt zusammen den murks.

@viegener: dem Sch.. hab ich ebenfalls _einige_ dunkle Stunden ;) zu verdanken.

igami

Zu dem Zeitpunkt wo ich Prüfe ist es ja noch gar kein JSON, sonder nur der Inhalt von DEF, bzw. der Teil eines Events:

sub msgDialog_Notify($$) {
  my ($hash, $dev_hash) = @_;
  my $SELF = $hash->{NAME};
  my $TYPE = $hash->{TYPE};
  my $device = $dev_hash->{NAME};

  return if(IsDisabled($SELF));

  my @events = @{deviceEvents($dev_hash, 1)};

  return unless(
       @events
    && AttrVal($SELF, "allowed", "") =~ m/(^|,)($device|everyone)(,|$)/
  );

  foreach my $event (@events){
    next unless($event =~ m/fhemMsgPushReceived: (.+)/);

    msgDialog_progress($hash, $device, $1);
  }

  return;
}


sub msgDialog_progress($$$;$) {
sub msgDialog_progress($$$;$) {
  my ($hash, $recipients, $message, $force) = @_;
  Debug("message is utf8") if(utf8::is_utf8($message));
  my $SELF = $hash->{NAME};
  my $TYPE = $hash->{TYPE};
  $recipients =
    $recipients eq "everyone" ?
      join(",", devspec2array(
          "TYPE=(ROOMMATE|GUEST):FILTER="
        . "msgContactPush=.+:FILTER=msgRecipientPush=.+"
      ))
    : $recipients;
  my @oldHistory;
  @oldHistory = split("\\|", ReadingsVal($SELF, $recipients."_history", ""))
    unless($force);
  push(@oldHistory, split("\\|", $message));
  my (@history);
  my $dialog =$hash->{DEF};
  Debug("dialog is utf8") if(utf8::is_utf8($dialog));
  ...


"utf8::valid" ist übrigens der Meinung, dass es utf8 ist  ???
Pi3 mit fhem.cfg + DbLog/logProxy
Komm vorbei zum FHEM Treffen im Kreis Gütersloh! Das nächste Mal im April 2020.

MAINTAINER: archetype, LuftdatenInfo, monitoring, msgDialog, Nmap, powerMap
ToDo: AVScene, FluxLED

viegener

Zitat von: herrmannj am 29 September 2017, 13:17:44
leider not so easy ...

utf8 kann ein bytestream (1-x mal 8 bit pro Zeichen) sein oder ein charstream (1 Zeichen darf > 8 bit sein).

Perl unterscheidet das nicht (so einfach).
is_utf8 gibt nur ein internes Flag zurück - unabhängig vom tatsächlichen Inhalt der Struktur.

Das, und verschiedene JSON und perl Versionen, ergibt zusammen den murks.

@viegener: dem Sch.. hab ich ebenfalls _einige_ dunkle Stunden ;) zu verdanken.

Genau diese Unterscheidung meine ich mit "markiert den String als unicode" -> downgrade setzt wohl intern im wesentlichen dieses Flag zurück (meine Vermutung - trial and error) - warum das auf manchen Installationen nötig ist und bei anderen nicht verstehe ich leider immer noch nicht genau, teile aber genau Deine Vermutung

Und absolut: Murks und überhaupt nicht easy :(
Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

Loredo

Zitat von: igami am 29 September 2017, 13:17:34
Die Nachricht wird über den msg Befehl abgesetzt und in dem Modul gibt es die Zeile 272

            eval '$o = decode_json( Encode::encode_utf8($1) ); 1';

In meinem Modul mache ich kein utf8 draus.
Ja, ist drin.


Dazu kann ich 2 Dinge ergänzen:


1. Ich hasse den Sch*** genauso  8)
2. Die zitierte Codezeile kommt eigentlich nicht mehr zum Einsatz, wenn man die neue Syntax des msg Befehls verwendet, die auf parseParams aufbaut. Das heißt momentan wird sich in dem msg Befehl gar nicht um Codierung gekümmert - wie es rein kommt so geht es an den set-Befehl des jeweiligen Moduls wieder raus (theoretisch).
Hat meine Arbeit dir geholfen? ⟹ https://paypal.me/pools/c/8gDLrIWrG9

Maintainer:
FHEM-Docker Image, https://github.com/fhem, Astro(Co-Maintainer), ENIGMA2, GEOFANCY, GUEST, HP1000, Installer, LaMetric2, MSG, msgConfig, npmjs, PET, PHTV, Pushover, RESIDENTS, ROOMMATE, search, THINKINGCLEANER