#!/usr/bin/perl

# Copyright (c) 2018-2019, AT&T Intellectual Property. All rights reserved.
#
# SPDX-License-Identifier: GPL-2.0-only

use strict;
use warnings;

use NetSNMP::ASN (':all');
use Time::Local;
use JSON qw( decode_json );

use lib "/opt/vyatta/share/perl5";
use Vyatta::MIBMisc qw(set_oid);
use Vyatta::SNMPSubagent;

my $snmp_subagent;

use constant ENTITY_REFRESH        => 180;    # seconds
use constant ENTITY_SENSOR_REFRESH => 60;     # seconds

# ENTITY-MIB (RFC 4133)
my $entityMIBObjects = ".1.3.6.1.2.1.47.1";
my $entityPhysical   = set_oid( $entityMIBObjects, 1 );
my $entPhysicalTable = set_oid( $entityPhysical, 1 );
my $entPhysicalEntry = set_oid( $entPhysicalTable, 1 );
my $entPhysicalIndex = set_oid( $entPhysicalEntry, 1 );
my $entPhysicalDescr = set_oid( $entPhysicalEntry, 2 );

# ENTITY-SENSOR-MIB (RFC 3433)
my $entitySensorMIBObjects      = ".1.3.6.1.2.1.99";
my $entitySensorObjects         = set_oid( $entitySensorMIBObjects, 1 );
my $entPhySensorTable           = set_oid( $entitySensorObjects, 1 );
my $entPhySensorEntry           = set_oid( $entPhySensorTable, 1 );
my $entPhySensorType            = set_oid( $entPhySensorEntry, 1 );
my $entPhySensorScale           = set_oid( $entPhySensorEntry, 2 );
my $entPhySensorPrecision       = set_oid( $entPhySensorEntry, 3 );
my $entPhySensorValue           = set_oid( $entPhySensorEntry, 4 );
my $entPhySensorOperStatus      = set_oid( $entPhySensorEntry, 5 );
my $entPhySensorUnitsDisplay    = set_oid( $entPhySensorEntry, 6 );
my $entPhySensorValueTimeStamp  = set_oid( $entPhySensorEntry, 7 );
my $entPhySensorValueUpdateRate = set_oid( $entPhySensorEntry, 8 );

my %EntitySensorDataType = (
    "other"      => 1,
    "unknown"    => 2,
    "voltsAC"    => 3,
    "voltsDC"    => 4,
    "volts"      => 4,
    "amperes"    => 5,
    "watts"      => 6,
    "hertz"      => 7,
    "celsius"    => 8,
    "percentRH"  => 9,
    "rpm"        => 10,
    "cmm"        => 11,
    "truthvalue" => 12,
);

my %EntitySensorDataScale = (
    "yocto" => 1,     #10^-24
    "zepto" => 2,     #10^-21
    "atto"  => 3,     #10^-18
    "femto" => 4,     #10^-15
    "pico"  => 5,     #10^-12
    "nano"  => 6,     #10^-9
    "micro" => 7,     #10^-6
    "milli" => 8,     #10^-3
    "units" => 9,     #10^0
    "kilo"  => 10,    #10^3
    "mega"  => 11,    #10^6
    "giga"  => 12,    #10^9
    "tera"  => 13,    #10^12
    "exa"   => 14,    #10^15
    "peta"  => 15,    #10^18
    "zetta" => 16,    #10^21
    "yotta" => 17,    #10^24
);

my %EntitySensorStatus = (
    "ok"             => 1,
    "unavailable"    => 2,
    "notapplicable"  => 2,
    "nonoperational" => 3,
);

sub get_sensor_data {
    my $data = `/opt/vyatta/bin/yangop-get-sensor sensor`;
    return if ( !defined($data) );
    my $results;
    eval { $results = decode_json($data); };
    return if ($@);
    return $results;
}

my $entPhysicalTable_columns = 18;

sub populate_entPhysicalTable {
    my $sensors = get_sensor_data();
    return if ( !defined($sensors) );

    my @sorted = sort { $a->{id} <=> $b->{id} } @$sensors;
    foreach my $e (@sorted) {
        my $id = $e->{id};

        $snmp_subagent->add_oid_int( $entPhysicalIndex, $id, $id );
        $snmp_subagent->add_oid_str( $entPhysicalDescr, $id, $e->{name} );
    }
}

sub populate_entPhySensorTable {
    my $sensors = get_sensor_data();
    return if ( !defined($sensors) );

    my $update_rate = ENTITY_SENSOR_REFRESH * 1000;
    my @sorted = sort { $a->{id} <=> $b->{id} } @$sensors;
    foreach my $e (@sorted) {
        my $id = $e->{id};

        $snmp_subagent->add_oid_int( $entPhySensorType, $id,
            $EntitySensorDataType{ $e->{"value-type"} } );
        $snmp_subagent->add_oid_int( $entPhySensorScale, $id,
            $EntitySensorDataScale{ $e->{"value-scale"} } );
        $snmp_subagent->add_oid_int( $entPhySensorPrecision, $id,
            $e->{"value-precision"} );
        $snmp_subagent->add_oid_int( $entPhySensorValue, $id, $e->{"value"} );
        $snmp_subagent->add_oid_int( $entPhySensorOperStatus, $id,
            $EntitySensorStatus{ $e->{"oper-status"} } );
        $snmp_subagent->add_oid_str( $entPhySensorUnitsDisplay, $id,
            $e->{"units-display"} );

        my ( $date, $time ) = split( /T/, $e->{"value-timestamp"} );
        my ( $year, $mon, $day ) = split( /-/, $date );
        my ( $hour, $min, $sec ) = split( /:/, $time );
        my $epoch_secs = timelocal( $sec, $min, $hour, $day, $mon-1, $year );
        $snmp_subagent->add_oid_timeticks( $entPhySensorValueTimeStamp, $id,
            int($epoch_secs) );

        $snmp_subagent->add_oid_unsigned( $entPhySensorValueUpdateRate, $id,
            $update_rate );
    }
}

$snmp_subagent = Vyatta::SNMPSubagent->new("vyatta-entity-mibs-subagent");

$snmp_subagent->register_oid( $entityMIBObjects, \&populate_entPhysicalTable,
    ENTITY_REFRESH );
$snmp_subagent->register_oid( $entitySensorMIBObjects,
    \&populate_entPhySensorTable,
    ENTITY_SENSOR_REFRESH );

$snmp_subagent->run();
