Python Forum
TKinter JSON Key Error
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
TKinter JSON Key Error
#1
Hi All, I am hoping someone can tell me why this error is happening with my line:
x = json.loads(sonoff01.text)
status = x['relays']
This code 'was' working fine, but I don't understand enough about json arrays and how they need to be called/used. My error is a Key Error for 'relays'. I updated my relay IP address and using a Sonoff Relay.

Here is my complete code:

from tkinter import *
from tkinter import messagebox
import json
import requests
import time
import os


ws = Tk() 
ws.title('Relay Control')
ws.geometry("600x400")
ws.configure(background='white')

on = PhotoImage(file = "frPorch_on.png")
off = PhotoImage(file = "frPorch_off.png")

sonoff01  = 'http://192.168.0.113/cm?cmnd=status+10'
sonURL = 'NOT_INIT'

sonURL = sonoff01
sonoff01 = requests.get(sonURL)
x = json.loads(sonoff01.text)
status = x['relays']
a = status
is_on = a[0]['ison']
print(is_on)

def Switch():
    global is_on

    if is_on:
        button.config(image = off)
        label.config(text = "Switch is Off", fg = "grey", bg='white')
        requests.post('http://192.168.0.113/relay/0/?turn=off')
        is_on = False

    else:

        button.config(image = on)
        label.config(text = "Switch is On", fg = "green", bg='white')
        requests.post('http://192.168.0.113/relay/0/?turn=on')
        is_on = True


if is_on == True:
    button = Button(ws, image = on, bg='white', bd = 0, command = Switch)
    button.pack(pady = 30)
    label = Label(ws, text = "The Switch Is On!", bg='white', fg = "green", font = ("Helvetica", 32)) 
    label.pack(pady = 20)
else:
    button = Button(ws, image = off, bg='white', bd = 0, command = Switch)
    button.pack(pady = 30)
    label = Label(ws, text = "The Switch Is Off!", bg='white', fg = "grey", font = ("Helvetica", 32)) 
    label.pack(pady = 20)


ws.mainloop()
Reply
#2
You are not working with json, you are working with lists and dictionaries. json.loads() creates a dictionary or a list. Do you know how lists and dictionaries work?

I would use a print statement or the debugger to get a look at what is returned by:
x = requests.get(sonURL).json()
print(x)
Reply
#3
(Jan-02-2023, 06:32 AM)deanhystad Wrote: You are not working with json, you are working with lists and dictionaries. json.loads() creates a dictionary or a list. Do you know how lists and dictionaries work?

I would use a print statement or the debugger to get a look at what is returned by:
x = requests.get(sonURL).json()
print(x)

Thanks deanhystad - I did try some prints of what is going on. Here are the outputs:

x = json.loads(sonoff01.text)
print(x)
Result: {'StatusSNS': {'Time': '2023-01-02T19:54:42', 'DS18B20': {'Id': '0316471BECFF', 'Temperature': 62.4}, 'TempUnit': 'F'}}

status = x['StatusSNS']
a = status
print(a)
Result: {'Time': '2023-01-02T19:54:42', 'DS18B20': {'Id': '0316471BECFF', 'Temperature': 62.4}, 'TempUnit': 'F'}

is_on = list(status.keys())[1:-1]
print(is_on)
Result: ['DS18B20']

temp_units = status["TempUnit"]
print(temp_units)
Result: F

So in my 'is_on' I am trying to get the state of the relay, but instead getting the temperature reading (which I will also be using later). I am not entirely clear on how these values are being read. I do not understand this line at all:

is_on = list(status.keys())[1:-1]
Reply
#4
status is a dictionary.
status.keys() are the keys in the dictionary. It returns a dict_keys object.
list(status.keys()) creates a list of the dictionary keys. This will be ['Time, 'DS18B20', 'TempUnit'].
list(status.keys())[1:-1] is a slice. It removes the first and last key from the list. This will be ['DS18B20'].

I looked up DS1820B and see it is a temperature sensor. I do not understand what it means for a temperature sensor to be "on" or "of". I would expect it to be "on" if it has power. Could you post a link to the API?
Reply
#5
** Ok, I think I have figured out some of it after making myself a bit crazy. I was actually trying to read the device information from the wrong section. This is a JSON file output from a SONOFF SWITCH using Tasmota Firmware. Here is what I have for now and it seems to be working as expected. However, it is messy and I know needs some cleaning. I come from VB.NET so Python has been much different to me for defined functions and how they get called.

I guess right now my question is: Do I create a def for the temperature? I also want to create a label to display the time, which I have the code, I just want to be sure I am laying it out correctly so I can call these in a correctly. I plan to add 3-4 additional switch/relay devices so I want to be sure it is done in a clean way.

from tkinter import *
from tkinter import messagebox
import json
import requests
import time
import os

ws = Tk() 
ws.title('Relay Control')
ws.geometry("600x400")
ws.configure(background='white')

on = PhotoImage(file = "lvgRoom_on.png")
off = PhotoImage(file = "lvgRoom_off.png")

sonoff01  = 'http://192.168.0.113/cm?cmnd=status'
sonURL = 'NOT_INIT'

sonURL = sonoff01
sonoff01 = requests.get(sonURL)

x = json.loads(sonoff01.text)
status = x['Status']
is_on = status["Power"]

#New Section for TEMPS --------------------------------------------
sonoffTemp = 'http://192.168.0.113/cm?cmnd=status+10'
tempURL = 'NOT_INIT'
tempURL = sonoffTemp
sonoffTemp = requests.get(tempURL)
i = json.loads(sonoffTemp.text)
statusT = i["StatusSNS"]
timestamp = statusT["Time"]
device_names = list(statusT.keys())[1:-1]
temp_units = statusT["TempUnit"]
templabel = Label(text="temp info", bg="White", fg="Black", font=("Helvetica", 12))
templabel.place(x=100, y=10)
print(timestamp)
#---------------------

for name in device_names:
    device = statusT[name]
    #print(f'ID={name}, Temperature={device["Temperature"]} {temp_units}')
    templabel.configure(text='Living Room '+f'Temperature: {device["Temperature"]} {temp_units}')


def Switch():
    global is_on

    if is_on:
        button.config(image = off)
        label.config(text = "Switch is Off", fg = "grey", bg='white')
        requests.post('http://192.168.0.113/cm?cmnd=Power Off')
        is_on = False
        
    else:
        button.config(image = on)
        label.config(text = "Switch is On", fg = "green", bg='white')
        requests.post('http://192.168.0.113/cm?cmnd=Power On')
        is_on = True


if is_on == True:
    button = Button(ws, image = on, bg='white', bd = 0, command = Switch)
    button.pack(pady = 30)
    label = Label(ws, text = "Switch Is On!", bg='white', fg = "green", font = ("Helvetica", 32)) 
    label.pack(pady = 20)
else:
    button = Button(ws, image = off, bg='white', bd = 0, command = Switch)
    button.pack(pady = 30)
    label = Label(ws, text = "Switch Is Off!", bg='white', fg = "grey", font = ("Helvetica", 32)) 
    label.pack(pady = 20)

ws.mainloop()
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [Tkinter] How to insert data json to treeview tkinter? Shakanrose 8 4,487 Jan-19-2023, 03:58 PM
Last Post: Shakanrose

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020