mrin / domoticz-routeros-plugin

Mikrotik RouterOS plugin for Domoticz
8 stars 2 forks source link

Added a few more metrics #10

Open drfranky1 opened 7 months ago

drfranky1 commented 7 months ago

I added a few more metrics, Total daliy traffic, total daily upload and total daily download. I'm sorry i put here the code but I can't open PR.

import Domoticz import math import os import sys

module_paths = [x[0] for x in os.walk(os.path.join(os.path.dirname(file), '.', '.env/lib/')) if x[0].endswith('site-packages')] for mp in module_paths: sys.path.append(mp)

from miktapi.sentence import sentence_pack, SentenceUnpacker from miktapi.helper import SentenceParser from miktapi.exceptions import UnpackerException, ParseException, PackException

class BasePlugin: bwOptions = {"Custom": "1;Mbit/s"} iconName = 'mikrotik-routeros-winbox' bwUpUnit = 1 bwDownUnit = 2 statusUnit = 3 totalTrafficUnit = 4 dailyDownloadUnit = 5 dailyUploadUnit = 6

statusOptions = {
    "LevelActions": "||",
    "LevelNames": "Disabled|Running|Enabled",
    "SelectorStyle": "0"
}

def __init__(self):
    self.miktLoggedIn = False
    self.miktAuthError = False
    self.miktConn = None
    self.miktUnpacker = SentenceUnpacker()
    self.statusInterfaceId = None
    self.statusRunning = None
    self.statusDisabled = None
    self.totalTrafficToday = {'rx': 0, 'tx': 0}

def onStart(self):
    if Parameters['Mode6'] == 'Debug':
        Domoticz.Debugging(1)
        DumpConfigToLog()

    if self.iconName not in Images:
        Domoticz.Image('icons.zip').Create()
    iconID = Images[self.iconName].ID

    if self.bwUpUnit not in Devices:
        Domoticz.Device(Name='Bandwidth UP', Unit=self.bwUpUnit, TypeName='Custom', Options=self.bwOptions,
                        Image=iconID).Create()
    if self.bwDownUnit not in Devices:
        Domoticz.Device(Name='Bandwidth Down', Unit=self.bwDownUnit, TypeName='Custom', Options=self.bwOptions,
                        Image=iconID).Create()
    if self.statusUnit not in Devices:
        Domoticz.Device(Name='Status', Unit=self.statusUnit, TypeName='Selector Switch', Image=iconID,
                        Options=self.statusOptions).Create()
    if self.totalTrafficUnit not in Devices:
        Domoticz.Device(Name='Total Traffic', Unit=self.totalTrafficUnit, TypeName='Custom', Options=self.bwOptions,
                        Image=iconID).Create()
    if self.dailyDownloadUnit not in Devices:
        Domoticz.Device(Name='Daily Download Traffic', Unit=self.dailyDownloadUnit, TypeName='Custom', Options=self.bwOptions,
                        Image=iconID).Create()
    if self.dailyUploadUnit not in Devices:
        Domoticz.Device(Name='Daily Upload Traffic', Unit=self.dailyUploadUnit, TypeName='Custom', Options=self.bwOptions,
                        Image=iconID).Create()

    self.miktConn = Domoticz.Connection(Name='Mikrotik', Transport='TCP/IP', Protocol='None',
                                        Address=Parameters['Address'], Port=Parameters['Port'])
    self.miktConn.Connect()

    Domoticz.Heartbeat(int(Parameters['Mode1']))

def onStop(self):
    if Parameters['Mode3'] and self.miktConn.Connected() and self.miktLoggedIn:
        self._miktCommand([
            '/cancel',
            '=tag=interface_status_update'
        ])
    self._miktResetLoginFlags()

def onConnect(self, Connection, Status, Description):
    self._miktResetLoginFlags()
    if Status == 0:
        Domoticz.Log('Mikrotik connected. Login...')
        self.miktConn.Send(sentence_pack(['/login', '.tag=initial_login']))
    else:
        Domoticz.Error("Mikrotik connection error.  Status [%s] [%s]" % (Status, Description))

def onMessage(self, Connection, Data):
    try:
        self.miktUnpacker.feed(Data)
        for sentence in self.miktUnpacker:
            reply, tag, words = SentenceParser.parse_sentence(sentence)

            if tag == 'initial_login' and reply == '!done':
                self.miktConn.Send(sentence_pack([
                    '/login',
                    '=name=%s' % Parameters['Username'],
                    '=password=%s' % Parameters['Password'],
                    '.tag=authorize'
                ]))

            elif tag == 'authorize' and reply == '!done' and not self.miktAuthError:
                Domoticz.Log('Mikrotik logged in successfully')
                self.miktLoggedIn = True
                if Parameters['Mode3']:
                    self._miktCommand([
                        '/interface/listen',
                        '=.proplist=.id,name,running,disabled',
                        '?name=%s' % Parameters['Mode3'],
                        '.tag=interface_status_update'
                    ])
                    self._miktCommand([
                        '/interface/print',
                        '=.proplist=.id,name,running,disabled',
                        '?name=%s' % Parameters['Mode3'],
                        '.tag=interface_status'
                    ])

            elif tag in ('interface_status', 'interface_status_update') and reply == '!re':
                if not self.statusInterfaceId:
                    self.statusInterfaceId = words.get('.id', None)
                if words.get('running', None) is not None:
                    self.statusRunning = words.get('running')
                if words.get('disabled', None) is not None:
                    self.statusDisabled = words.get('disabled')

                if self.statusRunning:
                    UpdateDevice(self.statusUnit, 1, '10', ShowInLog=True)
                elif self.statusDisabled:
                    UpdateDevice(self.statusUnit, 0, '0', ShowInLog=True)
                else:
                    UpdateDevice(self.statusUnit, 1, '20', ShowInLog=True)

            elif tag == 'bw' and reply == '!re':
                rx_bits = words.get('rx-bits-per-second', 0)
                tx_bits = words.get('tx-bits-per-second', 0)
                UpdateDevice(self.bwDownUnit, 1, str(bitToMbyte(rx_bits)), interface=words.get('.interface'))
                UpdateDevice(self.bwUpUnit, 1, str(bitToMbyte(tx_bits)), interface=words.get('.interface'))

                self.totalTrafficToday['rx'] += rx_bits
                self.totalTrafficToday['tx'] += tx_bits
                total_traffic = self.totalTrafficToday['rx'] + self.totalTrafficToday['tx']
                UpdateDevice(self.totalTrafficUnit, 1, str(bitToMbyte(total_traffic)))

                # Update daily download and upload traffic
                UpdateDevice(self.dailyDownloadUnit, 1, str(bitToMbyte(self.totalTrafficToday['rx'])))
                UpdateDevice(self.dailyUploadUnit, 1, str(bitToMbyte(self.totalTrafficToday['tx'])))

            elif tag == 'authorize' and reply == '!trap':
                self.miktAuthError = True
                Domoticz.Error('Mikrotik login error [%s]' % words.get('message', None))

            elif reply in ('!fatal', '!trap'):
                Domoticz.Error(
                    'Mikrotik error. Reply [%s]. Message [%s]. Tag [%s].' % (
                        reply, words.get('message', None), tag))

    except UnpackerException as e:
        Domoticz.Error('UnpackerException [%s]' % str(e))

    except ParseException as e:
        Domoticz.Error('ParseException [%s]' % str(e))

def onCommand(self, Unit, Command, Level, Hue):
    if self.statusUnit == Unit:
        if self.statusInterfaceId is None:
            Domoticz.Error('No interface ID')
            return

        if self.statusDisabled is None or self.statusRunning is None:
            Domoticz.Error('No current interface status')
            return

        # disable
        if Level == 0 and not self.statusDisabled:
            self._miktChangeInterfaceStatus(disabled=True)
        # run
        elif Level == 10 and not self.statusRunning:
            self._miktChangeInterfaceStatus(disabled=True)
            self._miktChangeInterfaceStatus(disabled=False)
        # enable
        elif Level == 20 and self.statusDisabled and not self.statusRunning:
            self._miktChangeInterfaceStatus(disabled=False)

def onDisconnect(self, Connection):
    self._miktResetLoginFlags()

def onHeartbeat(self):
    if not self.miktConn.Connected() and not self.miktConn.Connecting():
        Domoticz.Log('Mikrotik re-connecting...')
        self.miktConn.Connect()
    else:
        self._miktCommand([
            '/interface/monitor-traffic',
            '=interface=%s' % Parameters['Mode2'],
            '=once=yes',
            '=.proplist=rx-bits-per-second,tx-bits-per-second',
            '.tag=bw'
        ])

        # Reset daily traffic counters at the beginning of each day
        if self.isNewDay():
            self.totalTrafficToday['rx'] = 0
            self.totalTrafficToday['tx'] = 0

def _miktCommand(self, words_list):
    if self.miktLoggedIn and self.miktConn.Connected():
        try:
            self.miktConn.Send(sentence_pack(words_list))
        except PackException as e:
            Domoticz.Error('PackException [%s]' % str(e))

def _miktChangeInterfaceStatus(self, disabled):
    self._miktCommand([
        '/interface/set',
        '=disabled=%s' % ('yes' if disabled else 'no'),
        '=.id=%s' % self.statusInterfaceId,
        '.tag=interface_set'
    ])

def _miktResetLoginFlags(self):
    self.miktAuthError = False
    self.miktLoggedIn = False

def bitToMbyte(value): return math.ceil(value / (8 * 10 * 6) 100) / 100

def UpdateDevice(Unit, nValue, sValue, AlwaysUpdate=False, ShowInLog=False, interface=None): if interface: unitKey = (Unit, interface) else: unitKey = Unit

if unitKey not in Devices:
    return

if Devices[unitKey].nValue != nValue or Devices[unitKey].sValue != sValue or AlwaysUpdate:
    Devices[unitKey].Update(nValue, str(sValue))
    if ShowInLog:
        Domoticz.Log("%s: nValue %s - sValue %s" % (
            Devices[unitKey].Name,
            nValue,
            sValue
        ))

global _plugin _plugin = BasePlugin()

def onStart(): global _plugin _plugin.onStart()

def onStop(): global _plugin _plugin.onStop()

def onConnect(Connection, Status, Description): global _plugin _plugin.onConnect(Connection, Status, Description)

def onMessage(Connection, Data): global _plugin _plugin.onMessage(Connection, Data)

def onCommand(Unit, Command, Level, Hue): global _plugin _plugin.onCommand(Unit, Command, Level, Hue)

def onDisconnect(Connection): global _plugin _plugin.onDisconnect(Connection)

def onHeartbeat(): global _plugin _plugin.onHeartbeat()

def DumpConfigToLog(): for x in Parameters: if Parameters[x] != "": Domoticz.Debug("'" + x + "':'" + str(Parameters[x]) + "'") Domoticz.Debug("Device count: " + str(len(Devices))) for x in Devices: Domoticz.Debug("Device: " + str(x) + " - " + str(Devices[x])) Domoticz.Debug("Device ID: '" + str(Devices[x].ID) + "'") Domoticz.Debug("Device Name: '" + Devices[x].Name + "'") Domoticz.Debug("Device nValue: " + str(Devices[x].nValue)) Domoticz.Debug("Device sValue: '" + Devices[x].sValue + "'") Domoticz.Debug("Device LastLevel: " + str(Devices[x].LastLevel)) return