App-OpenHAP
view release on metacpan or search on metacpan
lib/Protocol/HAP/Server.pm view on Meta::CPAN
if $self->{cancel} && defined $self->{event_flush_timer};
$self->{event_flush_timer} = undef;
return;
}
# Send an EVENT/1.0 notification to the subscribed sessions, through
# the output contract. Do not send it to the originating session when
# the caller gives one (HAP-HTTP.md §14).
sub send_event ( $self, $aid, $iid, $value, $originator = undef )
{
my $key = "$aid.$iid";
my $subs = $self->{event_subscriptions}{$key} // {};
my $event_body = $self->{json}->encode( {
characteristics =>
[ { aid => $aid, iid => $iid, value => $value } ] }
);
my $event_msg = Protocol::HAP::HTTP::build_event($event_body);
for my $session ( values %$subs ) {
next unless $session && $session->is_encrypted;
next if defined $originator && $session == $originator;
$self->{output}->( $session, $session->encrypt($event_msg) );
}
return;
}
# --- identity and discovery -----------------------------------------------
sub is_paired ($self)
{
my $pairings = $self->{store}->load_pairings;
return scalar( keys %$pairings ) > 0;
}
sub add_accessory ( $self, $accessory )
{
$self->{bridge}->add_bridged_accessory($accessory);
return;
}
sub get_bridged_accessories ($self)
{
return $self->{bridge}->get_bridged_accessories;
}
sub get_config_number ($self)
{
return $self->{store}->get_config_number;
}
# $self->update_config_number:
# Increment c# when the accessory database changed since the
# last run (HAP-mDNS.md §3.1). The host calls this after
# device loading. It compares a digest of the accessory
# structure against the stored one.
sub update_config_number ($self)
{
my @parts;
for my $accessory ( $self->{bridge}->get_all_accessories ) {
push @parts, "a$accessory->{aid}";
for my $service ( $accessory->get_services ) {
push @parts,
"s$service->{iid}:" . $service->to_json->{type};
for my $char ( $service->get_characteristics ) {
push @parts,
"c$char->{iid}:"
. $char->to_json->{type} . ':'
. $char->{format};
}
}
}
my $digest = unpack( 'H*', sha512( join( ';', @parts ) ) );
my $stored = $self->{store}->get_config_digest;
if ( !defined $stored ) {
# On the first run, record the digest. c# stays at
# its initial value of 1.
$self->{store}->save_config_digest($digest);
}
elsif ( $stored ne $digest ) {
$self->{store}->increment_config_number;
$self->{store}->save_config_digest($digest);
$self->{logger}
->info( 'Accessory database changed, c# is now %d',
$self->get_config_number );
}
return $self->get_config_number;
}
sub get_device_id ($self)
{
return Protocol::HAP::device_id( $self->{accessory_ltpk} );
}
# $self->mdns_txt_records:
# The TXT records of the advertisement, as a hash reference
# [HAP-mDNS §3]. The host formats and publishes them; the wire
# format belongs to the host's mDNS responder, not to HAP.
sub mdns_txt_records ($self)
{
# Note: pv=1, not 1.1. mdnsd uses '.' as the TXT record
# delimiter and does not support escaping. HomeKit accepts
# pv=1.
my $records = {
'c#' => $self->get_config_number,
'ff' => 0,
'id' => $self->get_device_id,
'md' => $self->{name},
'pv' => '1',
's#' => 1,
'sf' => $self->is_paired ? 0 : 1,
'ci' => $self->{category},
};
( run in 3.164 seconds using v1.01-cache-2.11-cpan-364913b4093 )