device 'simulator'

Begonnen von justme1968, 13 September 2015, 22:59:01

Vorheriges Thema - Nächstes Thema

justme1968

da ich schon öfter in die verlegenheit gekommen bin ein bestimmtes device aus dem setup eines anwenders nachzustellen und das jetzt gerade mit der homebridge/siri integration wieder akut geworden ist habe ich mir die folgenden beiden kleinen hilfsroutinen geschrieben um aus einer jsonlist2 die der anwender posten kann eine möglichst exakte kopie dieses devices wieder herzustellen.

diese kopie kann auf einem dummy basieren oder das tatsächliche device modul verwenden. im dummy fall wird versuch über die setList und readingList attribute auch das aussehen und verhalten unter im webfrontend ein wenig nachzubilden. durch ein paar optionale parameter lassen sich dinge wie device name, die übername von internals, readings und attributen sowie die setList/readingList beeinflussen. die json daten können direkt als string übergeben oder aus einem file gelesen werden.

es gibt zwei routinen die aufeinander aufbauen:

  • jsonlist2dummy($json;$name): erzeugt aus einer jsonlist2 ein dummy.
    $json kann als json string oder als file name angegeben werden.
    in $name kann optional der zu verwendende name übergeben werden. wenn nichts angeben wird dann wird der device aus dem ursprünglichen namen und einem angehängten FromJson gebildet.


  • jsonlist2device($json;$defaults): erzeugt aus einer jsonlist2 ein device mit dem ursprünglichen TYPE.
    $json kann als json string oder als file name angegeben werden.
    $defaults ist ein optionaler hash in dem über die keys NAME, TYPE, DEF, Internals, Readings, Attributes und PossibleSets jeweils der betreffende teil aus der jsonlist überschrieben werden kann. ein beispiel für die verwendung ist in jsonlist2dummy zu sehen.
    im überschriebenen namen wird der platzhalter # durch den tatsächlichen device namen ersetzt.

das ganze ist natürlich nicht perfekt aber für viele fälle bei denen es 'nur' um frontend entwicklung geht eine recht gute näherung. vielleicht nützt es ja noch anderen um beim entwickeln bestimmte szenarien und devices nachzustellen.

eine mögliche verbesserungen könnten noch sein einen readingsProxy statt des normalen dummy zu verwenden um die set kommandos realistischer nachzubilden und auch noch mögliche get kommandos zu simulieren.

gruss
  andre

sub
jsonlist2device($;$)
{
  my($json, $defaults) = @_;

  if( $json !~ m/^\s*{.*}\s*$/ ) {
    local $/ = undef;
    open FILE, $json or die "Couldn't open file: $!";
    binmode FILE;
    $json = <FILE>;
    close FILE;
  }

  use JSON;
  my $decoded = decode_json($json);

  foreach my $device (@{$decoded->{Results}}) {
    my $name = $device->{Internals}->{NAME};
    my $type = $device->{Internals}->{TYPE};
    my $def = $device->{Internals}->{DEF};
    $def = "" if( !defined($def) );

    $name = $defaults->{NAME} if( $defaults->{NAME} );
    $name =~ s/#/$device->{Internals}->{NAME}/;
    $type = $defaults->{TYPE} if( $defaults->{TYPE} );
    $def = $defaults->{DEF} if( defined($defaults->{DEF}) );

    $device->{Internals} = $defaults->{Internals} if( defined($defaults->{Internals}) );
    $device->{Readings} = $defaults->{Readings} if( defined($defaults->{Readings}) );
    $device->{Attributes} = $defaults->{Attributes} if( defined($defaults->{Attributes}) );
    $device->{PossibleSets} = $defaults->{PossibleSets} if( exists($defaults->{PossibleSets}) );

    my $ret = CommandDefine(undef, "$name $type $def");
    if( $ret ) {
      Log3 undef, 1, "jsonlist2device: $ret" if( $ret );
      return undef;
    }   

    foreach my $internal (keys %{$device->{Internals}} ) {
      next if( $internal eq 'NAME' );
      next if( $internal eq 'TYPE' );
      next if( $internal eq 'DEF' );
      next if( $internal eq 'CFGFN' );
      $defs{$name}->{$internal} = $device->{Internals}->{$internal};
    }   

    my $readingList;
    foreach my $reading (keys %{$device->{Readings}} ) {
      $defs{$name}->{READINGS}->{$reading} = { VAL => $device->{Readings}->{$reading}->{Value},
                                               TIME => $device->{Readings}->{$reading}->{Time} };

      $readingList .= ' ' if( $readingList );
      $readingList .= $reading;
    }   

    foreach my $attr (keys %{$device->{Attributes}} ) {
      $attr{$name}->{$attr} = $device->{Attributes}->{$attr};
    }   

    if( $type eq 'dummy'
        && $device->{PossibleSets}
        && !defined( $attr{$name}->{setList}) ) {
      $attr{$name}->{setList} = $device->{PossibleSets};

      if($readingList
          && !defined( $attr{$name}->{readingList}) ) {
        $attr{$name}->{readingList} = $readingList;
      }   
    }   

  }
}

sub
jsonlist2dummy($;$)
{
  my($json,$name) = @_;

  $name = '#FromJson' if( !$name );

  jsonlist2device( $json, { TYPE => 'dummy', NAME => $name, DEF => '' } );

}
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968