Data-Monkey/Pi.Alert

MQTT / get_all_devices(db)

Data-Monkey opened this issue · 11 comments

In code

def mqtt_start(db):    

    #global client

    if conf.mqtt_connected_to_broker == False:
        conf.mqtt_connected_to_broker = True           
        client = mqtt_create_client() 
    
    # General stats    

    # Create a generic device for overal stats
    create_generic_device(client)

    # Get the data
    row = get_device_stats(db)   

    columns = ["online","down","all","archived","new","unknown"]

    payload = ""

    # Update the values 
    for column in columns:       
        payload += '"'+column+'": ' + str(row[column]) +','  

The following error is thrown when an MQTT notification is raised:

pialert    | Traceback (most recent call last):
pialert    |   File "/usr/lib/python3.9/runpy.py", line 197, in _run_module_as_main
pialert    |     return _run_code(code, main_globals, None,
pialert    |   File "/usr/lib/python3.9/runpy.py", line 87, in _run_code
pialert    |     exec(code, run_globals)
pialert    |   File "/home/pi/pialert/pialert/__main__.py", line 314, in <module>
pialert    |     sys.exit(main())
pialert    |   File "/home/pi/pialert/pialert/__main__.py", line 277, in main
pialert    |     send_notifications(db)
pialert    |   File "/home/pi/pialert/pialert/reporting.py", line 307, in send_notifications
pialert    |     mqtt_start(db)
pialert    |   File "/home/pi/pialert/pialert/publishers/mqtt.py", line 165, in mqtt_start
pialert    |     payload += '"'+column+'": ' + str(row[column]) +','
pialert    | TypeError: list indices must be integers or slices, not str

Seems like:

#-------------------------------------------------------------------------------
def get_device_stats(db):
    # columns = ["online","down","all","archived","new","unknown"]
    return db.read(sql_devices_stats)

returns an incorrect DataType.

I might be wrong though... havent't used db.read() before.

⚠Please also double check if def get_all_devices(db): returns the correct type as part of this fix.

I think you are correct.
My db.read is a fetchall while we just want fetchone.
I have added a db.read_one() to make it compatible again.

    def read_one(self, query, *args):
        """ 
        call read() with the same arguments but only returns the first row.
        should only be used when there is a single row result expected
        """

        mylog('debug',[ '[Database] - Read One: ', query, " params: ", args])
        rows = self.read(query, *args)
        if len(rows) > 1: 
            mylog('none',[ '[Database] - Warning!: query returns multiple rows, only first row is passed on!', query, " params: ", args])
            return rows[0]
        return None

getting this now:

pialert    | Traceback (most recent call last):
pialert    |   File "/usr/lib/python3.9/runpy.py", line 197, in _run_module_as_main
pialert    |     return _run_code(code, main_globals, None,
pialert    |   File "/usr/lib/python3.9/runpy.py", line 87, in _run_code
pialert    |     exec(code, run_globals)
pialert    |   File "/home/pi/pialert/pialert/__main__.py", line 314, in <module>
pialert    |     sys.exit(main())
pialert    |   File "/home/pi/pialert/pialert/__main__.py", line 276, in main
pialert    |     send_notifications(db)
pialert    |   File "/home/pi/pialert/pialert/reporting.py", line 307, in send_notifications
pialert    |     mqtt_start(db)
pialert    |   File "/home/pi/pialert/pialert/publishers/mqtt.py", line 165, in mqtt_start
pialert    |     payload += '"'+column+'": ' + str(row[column]) +','
pialert    | TypeError: 'NoneType' object is not subscriptable

I put a lot of debug messages around the database, can you set the log to debug and see what you get.
Essentially there is None returned from the read or read_one function

Crashing just after:

14:33:47 [updateState] changing state to: "Send: MQTT"
14:33:47 [Notification] Establishing MQTT thread
14:33:47         Connected to broker
14:33:59 [Database] - Read One: SELECT Online_Devices as online, Down_Devices as down, All_Devices as 'all', Archived_Devices as archived, (select count(*) from Devices a where dev_NewDevice = 1 ) as new, (select count(*) from Devices a where dev_Name = '(unknown)' or dev_Name = '(name not found)' ) as unknown from Online_History order by Scan_Date desc limit  1 params: ()
14:33:59 [Database] - Read All: SELECT Query: SELECT Online_Devices as online, Down_Devices as down, All_Devices as 'all', Archived_Devices as archived, (select count(*) from Devices a where dev_NewDevice = 1 ) as new, (select count(*) from Devices a where dev_Name = '(unknown)' or dev_Name = '(name not found)' ) as unknown from Online_History order by Scan_Date desc limit  1 params: ()
14:34:00 

Difficult with async processes :/

got this weird incomplete log:

pialert    | 14:33:42 [New Devices] 4 Pi-hole Create devices
pialert    | Traceback (most recent call last):
pialert    |   File "/usr/lib/python3.9/runpy.py", line 197, in _run_module_as_main
pialert    |     return _run_code(code, main_globals, None,

This is how get_device_stats looked before the split up:

https://github.com/jokob-sk/Pi.Alert/blob/070e31ef191a1b0f195aa7b5a373ffcfc31922fa/back/pialert.py#L3590

def get_device_stats():

    # columns = ["online","down","all","archived","new","unknown"]
    sql.execute(sql_devices_stats)

    row = sql.fetchone()
    commitDB()

    return row

I removed some commits as I believe they are not required on read. But maybe they are ....

Also the sql_devices_stats is limiting its output to one record anyway, it should always return just the one record.
Maybe I change the read_one() to do the fetchone rather than just returning the first record of the read()

read_one() was actually not working, fixed it now

Thanks! Now I'm getting:

pialert    | 18:28:29 [updateState] changing state to: "Send: MQTT"
pialert    | 18:28:29 [Notification] Establishing MQTT threadTraceback (most recent call last):
pialert    |   File "/usr/lib/python3.9/runpy.py", line 197, in _run_module_as_main
pialert    |     return _run_code(code, main_globals, None,
pialert    |   File "/usr/lib/python3.9/runpy.py", line 87, in _run_code
pialert    |     exec(code, run_globals)
pialert    |   File "/home/pi/pialert/pialert/__main__.py", line 314, in <module>
pialert    |     sys.exit(main())
pialert    |   File "/home/pi/pialert/pialert/__main__.py", line 276, in main
pialert    |     send_notifications(db)
pialert    |   File "/home/pi/pialert/pialert/reporting.py", line 307, in send_notifications
pialert    |     mqtt_start(db)
pialert    |   File "/home/pi/pialert/pialert/publishers/mqtt.py", line 178, in mqtt_start
pialert    |     devices = get_all_devices()
pialert    | TypeError: get_all_devices() missing 1 required positional argument: 'db'
pialert    |
pialert    | 18:28:29         Connected to broker

silly mistake hopefully fixed now.
It is a long weekend here in Australia this weekend, I will be away for the weekend and won't be able to progress this further until next week.

Thanks!
Enjoy the long weekend!

🎉 MQTT seems up and running
image

Thank you! 👍