Giter Club home page Giter Club logo

nspanelmanager's Introduction

NSPanelManager

What is it?

This project aims to solve the issue with having multiple Sonoff NSPanels installed around the house and having to make code changes as soon as you want to make a change. The project also aims to be simple to use, work for both Home Assistant and OpenHAB and any other home automation tool that can leverage MQTT.

The concept

The idea is that by using the same layout on all the different panels all users will quickly become accustomed to the layout and usage of the panel.

More information

All information about this project on how it works and how to use it is available in the User & Technical reference manual available here.

Note: For the best experience, download the PDF. It has helpful links (any text in blue) that doesn't work in the GitHub PDF viewer. Also, the GitHub PDF viewer only shows a few pages at the time.

Further questions or discussion?

Head over to our Discord!

Support

Buy Us A Coffee

nspanelmanager's People

Contributors

cablesandcoffee avatar emmaly avatar jamesmulcahy avatar phaeton82 avatar tpanajott avatar velijv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nspanelmanager's Issues

Individual Lights page functionality

Suggested behavior:
Entering page by pressing a Brightness Lights:
Only Brightness slider visble

Entering page by pressing a Brightness and Color Temp Light:
Brightness and Color Temp Slider are visible.

Entering page by pressing a Brightness, Color Temp and Color Light:
Brightness and Color Temp Slider are visible. Color symbol in top right corner visible.
By pressing the color symbol user toggles color mode.

  • Color symbol in top right corner changes to color temp symbol.
  • Color temp slider should disappear, Saturation and Color slider should appear.
    Pressing color temp symbol toggles back to color temp mode.

Add space characters on room page rows

Somehow we need some spacing to the left of each device name on room page. I solved it before by adding two spaces.

Is it possible to add two space characters before the name on each device row?

In Nextion there is no spacing functionality for a text box but we need to have the text box as big as the button so the press event change background on the entire button. That's why my only idea is to add two spaces.

Ceiling lights button does not act as Table Lights button at all times

Setup: Room lights mode. Turn Table and Ceiling Lights ON. Change Brightness to 100% and kelvin to 100%. Press Ceiling and Table lights buttons to turn all lights OFF.

Scenario:
Press Ceiling lights button. Ceiling lights turns on. No movement in either Brightness or Kelvin slider. (Correct)
Press Table lights button. Table lights turns on. No movement in either Brightness or Kelvin slider. (Correct)

Lock Ceiling button. Change Kelvin slider to about 50%
Lock Table button. Change Kelvin slider to about 25%

Press Ceiling lights button to turn ceiling lights off.
Press Table lights button to turn table lights off.

Press Table lights button to turn table lights on. No movement in kelvin slider (Correct)
Press Ceiling lights button to turn ceiling lights ON. Movement in kelvin slider (Incorrect)

Ceiling and Table lights behaves differently in this scenario. Table lights behavior feels more correct. Some value seems to be kept after having done lock stuff to the buttons but it only affects the ceiling button.

Wrong/No MQTT user/pass blocks panel from being found

When configuring the panel as a test I havent added a user/pass to the configuration. In my Mosquitto logs I can see the device being rejected. In NSPanelManager the panel doesn't appear. It seems that if the device cannot access MQTT it doesn't appear.

I'd suppose it might be nice to be able to correct the mistake from NSPanelManager.

Update
Due to the wifi connection being made I could enter the web interface of the device. It allowed me to fix the issue. An update to the docs (FAQ?) might be helpfull. Even though it might be preferable to be able to fix this from the manager (for less advanced users)

Dynamic approach to room pages

I'm thinking about the design of the room pages. Today it looks like this:

roomnoTV_switches_ON

My suggestion is something simular to this instead:

NSPM room

This is probably the easiest way. There's no fancy smancy icons but it's very dynamic from a user perspective. Up to 12 things in every room and the availability to go deeper into each thing by pressing on a specific item row.

Suggestion is that all light positions for that room auto populates in the same order that they are in NSPanel Manager.
Starting from left and continuing on right column if lights are more than 6. Pressing on a lights row will bring up the lights page for controlling of that lights capabilities. Or the user should be able to completely decide which row which light will be on. Maybe a user wants to have ceiling lights on left column and the rest of the lights on the right. Or something else. Maybe a row number could be added to the database to tell what item will end up on which row? I think the user should be able to decide on which row a specific item should end up on to be able do create natural spaces if not using all rows. Like in the example picture.

The rest of the rows will be for other smart devices in that room. Coffee brewer, TV's, curtains and so on.
Suggestion is also that some predefined functions can be chosen for specific rows. So if you're saying that one of the rows is a TV you will end up on a TV page when pressing the text for that row. If it's a curtain we can design a specific curtain page to take care of that. There is really no hurry with these predefined functions and function pages but designing it this way gives us flexibility further on to send the user to function pages such as TV, Coffee, Curtains and so on that the user could have in there room.

And of course the text and switch for the rows that does not have an item should be hidden away on page load.

Lock ceiling/table bugg

Something strange can occur when using the ceiling/table lock function.

Way to reproduce:
Enter lock mode by holding table icon (Yellow lines appears)
Short press on ceiling button (Yellow lines disappear)
Then short press again on table button. (Yellow lines appears again)
After that if you continue to short press either table or ceiling symbol it toggles on and off the yellow lines.

Physical buttons functionality!

User should be able to choose what the physical buttons does.

User choices that I can think of:

  1. Use button to turn on and off panel relay = Kill power to light

  2. Bind room light to physical button. Similar to adding lights on room page.

  3. Maybe user wants neither 1 or 2. Give the option to add a switch for example.

All lights mode, no lights ON + changing Brightness slider

Current behaviour:
Panel in All lights mode
No lights on
Changing Brightness dimmer results in all lights turning on even lights that does not exist.

Expected behaviour:
Only lights that are currently on should change.
If no lights are on only lights that exist should turn on.

Add new buttons to drop-down on NSPanel

When a user pulls down the menu in the top of the panel, add an option to reboot the panel. This might be required if the panel for some reason disconnects from the WiFi as it is the no longer possible to reboot it from NSPanelManager.

It would also be helpful to have a button to factory reset the panel in case someone changes WiFi name and/or password and it can no longer connect. Currently, if this happens a user needs to re-flash the firmware.

Implement panel status reporting

Implement status reporting from the panel back to MQTTManager that would feed the information into the database so that it can be displayed on the web interface. The information I'm thinking of currently is the following:

  • Online/Offline status
  • RSSI (WiFi) signal strength
  • Display on/off (could be tied in with #17 )
  • Free memory

All Lights mode + change Kelvin turn lights ON

Current behaviour:
Panel in All lights mode. No lights on. Changing Kelvin turns all lights on even those that does not exist.

Expected behaviour:
Only lights that are already on should receive the kelvin value.

Addon logs while starting

Still the webserver seems working though at http://homeassistant.local:8000/

  • room 1 is the "Dummy Room"
  • room 2 is my created:

homeassistant local_8000_rooms_2_


INFO:root:Connecting to Home Assistant at ws://supervisor/core/websocket
INFO:root:WebSocket connection to Home Assistant opened.
INFO:root:Sending auth to Home Assistant
INFO:root:Home Assistant auth OK. Requesting existing states.
[17/Jul/2023 09:55:17] "POST /api/set_panel_online_status/C0:49:EF:F8:CD:48/ HTTP/1.1" 200 0
[17/Jul/2023 09:56:14] "POST /api/set_panel_online_status/C0:49:EF:F8:CD:48/ HTTP/1.1" 200 0
INFO:root:Connected to MQTT Server
[17/Jul/2023 09:56:16] "POST /api/set_panel_online_status/C0:49:EF:F8:CD:48/ HTTP/1.1" 200 0
[17/Jul/2023 09:56:16] "POST /api/set_panel_online_status/C0:49:EF:F8:CD:48/ HTTP/1.1" 200 0
[17/Jul/2023 09:56:17] "POST /api/set_panel_online_status/C0:49:EF:F8:CD:48/ HTTP/1.1" 200 0
[17/Jul/2023 09:56:48] "POST /api/set_panel_online_status/C0:49:EF:F8:CD:48/ HTTP/1.1" 200 0
[17/Jul/2023 09:57:17] "POST /api/set_panel_online_status/C0:49:EF:F8:CD:48/ HTTP/1.1" 200 0
[17/Jul/2023 09:57:47] "POST /api/set_panel_online_status/C0:49:EF:F8:CD:48/ HTTP/1.1" 200 0
[17/Jul/2023 09:58:17] "POST /api/set_panel_online_status/C0:49:EF:F8:CD:48/ HTTP/1.1" 200 0
[17/Jul/2023 09:58:38] "GET /checksum_firmware HTTP/1.1" 200 32
[17/Jul/2023 09:58:39] "GET /checksum_data_file HTTP/1.1" 200 32
/usr/local/lib/python3.11/site-packages/django/db/models/fields/__init__.py:1564: RuntimeWarning: DateTimeField NSPanel.last_seen received a naive datetime (2023-07-17 09:58:52.784416) while time zone support is active.
  warnings.warn(
[17/Jul/2023 09:58:52] "POST /api/set_panel_online_status/C0:49:EF:F8:CD:48/ HTTP/1.1" 200 0
[17/Jul/2023 09:58:52] "POST /api/register_nspanel HTTP/1.1" 200 2
[17/Jul/2023 09:58:53] "POST /api/set_panel_online_status/C0:49:EF:F8:CD:48/ HTTP/1.1" 200 0
[17/Jul/2023 09:58:54] "GET /api/get_nspanels_warnings HTTP/1.1" 200 88
[17/Jul/2023 09:58:54] "GET /api/get_nspanel_config?mac=C0:49:EF:F8:CD:48 HTTP/1.1" 200 756
[17/Jul/2023 09:58:56] "GET /api/get_nspanel_config/room/1 HTTP/1.1" 200 50
[17/Jul/2023 09:58:56] "GET /api/get_nspanel_config/room/2 HTTP/1.1" 200 459
ERROR:root:Something went wrong during processing of message:
Traceback (most recent call last):
  File "/usr/src/app/./mqtt_manager.py", line 121, in on_message
    if msg.payload.decode() == "":
       ^^^^^^^^^^^^^^^^^^^^
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 139: invalid start byte
ERROR:root:Something went wrong when processing the exception message, couldn't decode payload to utf-8.
[17/Jul/2023 09:58:57] "GET /api/get_nspanel_config?mac=C0:49:EF:F8:CD:48 HTTP/1.1" 200 756
[17/Jul/2023 09:58:57] "GET /api/get_nspanel_config/room/1 HTTP/1.1" 200 50
[17/Jul/2023 09:58:57] "GET /api/get_nspanel_config/room/2 HTTP/1.1" 200 459

Lock button incosistent behavior

Scenario:
Room Lights mode. All Ceiling and Table Lights OFF

  1. Hold TABLE button to activate table lock function.
    Result:
    Yellow brightness line turns yellow on current position. (Correct)
    Yellow Kelvin line turns yellow on the current position. (Correct)

  2. Hold CEILING button to activate table lock function.
    Result:
    Yellow brightness line turns yellow on current position. (Correct)
    Yellow Kelvin line turns yellow but changes position. (Incorrect)

All lights mode, table lights on in one room + changing brightness dimmer

Expected Behavior
Only the lights that are currently on in house should change. Ceiling or table lights symbols that are off in other rooms should not become yellow.

Actual Behavior
Only the lights that are on changes in real life.
But when switching to another room the table lights symbol has become yellow there as well all though those lights are not on.

Update Add lights window to support Switches

Current behaviour
Currently an Openhab user is able to add a light that is of type Switch in the Add lights window but Openhab throws an error when NSPM is sending a percent value to the switch and the light is neither turned on or off.

Error from Openhab log:
[hab.core.io.websocket.EventWebSocket] - Failed to process deserialized event '{"type": "ItemCommandEvent", "topic": "openhab/items/Outlet2LightsMirror_Brightness/command", "payload": "{\"type\":\"Percent\",\"value\":\"0\"}", "source": "WebSocketNSPanelManager"}': Incompatible datatype, rejected.

Expected Behaviour
If brightness slider > 0 a light of type Switch should turn on
If brightness slider = 0 light of type Switch should turn off

Solution:
Add "Switch" as capability in Add lights window to know when to use the payload shown below.

For switches the payload sent on Openhab websocket must look like this:
"payload": "{"type":"OnOff","value":"ON"}"

Update New Lights window to show Item choices based on Capabilities

Not sure if this affects the Home Assistant users so tagged as Openhab related.

Current behavior:
When adding a light all possible Item choices are shown all though maybe only Dimming capability has been chosen.

Future behavior:
Show Item choices based on which capabilities the user has chosen for the specific light.

Solution suggestion:

  1. User adds new light

  2. Chooses Thing

  3. Add new light to room-window appears

  4. No capabilities are pre-chosen. No Item drop downs are available either.

  5. User ticks in capabilities for light

  6. For each capability chosen Item drop downs appear.

I guess it should not be possible to choose Dimmable and Switch capability on the same light?
The only purpose of being able to chose Switch is to be able to control a light that is controlled via an outlet.
I'm saying this because a user in Openhab can have a switch and dimmer Item connected to the same channel and might make that choice but we are in no use of knowing that. It just complicates things. If light is dimmable capable that is the choice the user needs to make.

If Switch is chosen: All other capabilites are grayed out?
If Dimmable is chosen: Switch is Grayed out?

Some UX remarks

General

Even after reading the #documentation #pdf, I didn't know if i needed to create 2 mqtt users, 1 for manager, 1 for panel or could I use the same for both?

Manager view (HA Addon)

Navigation

  1. NSpanels - OK, even the logo redirects to same page. Can be removed.
  2. Rooms: Screenshot 2023-07-17 at 20 28 54
    2.a. The main link is the same as the first one of the dropdown. Remove dropdown first link.
    2.b. Change order - can be in general room manager by drag-drop. Remove link.
    2.c. New room - remove link, since in main Room view the main CTA is Add new room anyway.
  3. Upload: this confused me. Do I upload it to the manager, and then install to my NSPanel? What is a data file? Is this for beta testers only?
  4. Settings:
    4.a. Changes to NSPanel settings on this page requires a reboot of each panel to take effect. - can we automatically reboot?

Index page (/)

  • the list looks very narrow and empty, with most people having 1 or 2 devices at most
Screenshot 2023-07-17 at 20 17 56

Suggest a grid with "card" styles, quick mockup:
Screenshot 2023-07-17 at 20 25 10

  • Maybe still too much info which duplicates each other. If it has wifi RSSI icon, then i can deduce it is online.
  • The Actions are hidden under a dropdown - there are only 3 of them, could be all visible, or moved to the individual device page.

Rooms page

  • Save and Delete next to each other compete a bit, the delete could be in the corner with just an icon.

Add a light

There are competing options which invalidate each other.

Screenshot 2023-07-17 at 20 37 50
  • If it is a switch, it has no "Capabilities" (temp, rgb)
  • The Color temperature and RGB confuse me - if I have an RGB light, it also has (in HASS) color temperature changing option anyway.
  • The parameters (at least from HASS) can be grabbed and autofilled, ie:
    <template TemplateState(<state light.kitchen_ceiling=off; supported_color_modes=[<ColorMode.ONOFF: 'onoff'>], icon=fapro:yeelight-filament, friendly_name=Ceiling, supported_features=0, logo=yeelight @ 2023-07-17T19:44:43.869083+03:00>)>

Individual light control

I don't get this bottom picture at all, it seems almost like a live demo of what i can expect on the NSPanel, but it is not, so what is it?
Screenshot 2023-07-17 at 20 44 44

Clicking on any cell gives this popup, what am I supposed to do?

Screenshot 2023-07-17 at 20 46 08

Single device page (http://192.168.1.xxx)

  • Add link to the Manager page (http://homeassistant.local:8000/)
  • Add link to the NSpanel inside manager (http://homeassistant.local:8000/nspanel/1)
  • Friendly name - since it can be changed in Manager/nspanel, why duplicate it?
  • If already connected to Wifi, remove the Wifi block? Same with MQTT.
  • Show the same stats here as Manager Index page (Temperature, RSSI), and the actions?
  • NSPanel TFT upload block - move to Manager page, since I can't upload the TFT from here anyway?

Source: personal preferences and have worked in the area for 15 years.

Room page needs "touch caps"

The "Room" page needs the same treatment as the home page, by blocking the user from touching the switch directly.

Add long press to save button on Scenes page to prevent from accidentaly saving a scene because of chipsfingrar. + cool save progress bar

There is an item prepared in the HMI file to act as progress bar.
Here's my suggestion:
Someone presses a save button.
Make item "slider_save" visible on HMI
Start changing "slider_save" value from 0-100
If the user long presses the amount of time it takes for the progress bar to get to 100:
Text changes so something like "Scene saved" and the scene is saved
If user releases before slider is 100:
slider_save disappears and scene is not saved.

Bootscreen now showing on boot

When starting the NSPanel, the bootscren is not shown. Implement "connect"-command to wait for panel to be ready before proceeding with the InterfaceManager.

Database is locked

Using HomeAssistant Addon.
Whille managing rooms and lights, when TFT was uploading:

OperationalError at /add_light/2
database is locked
Request Method:	POST
Request URL:	http://homeassistant.local:8000/add_light/2
Django Version:	4.1.7
Exception Type:	OperationalError
Exception Value:	
database is locked
Exception Location:	/usr/local/lib/python3.11/site-packages/django/db/backends/sqlite3/base.py, line 357, in execute
Raised during:	web.views.add_light_to_room
Python Executable:	/usr/local/bin/python
Python Version:	3.11.4
Python Path:	
['/usr/src/app/nspanelmanager',
 '/usr/local/lib/python311.zip',
 '/usr/local/lib/python3.11',
 '/usr/local/lib/python3.11/lib-dynload',
 '/usr/local/lib/python3.11/site-packages']
Server time:	Mon, 17 Jul 2023 03:17:26 +0000





Environment:


Request Method: POST
Request URL: http://homeassistant.local:8000/add_light/2

Django Version: 4.1.7
Python Version: 3.11.4
Installed Applications:
['web',
 'mathfilters',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
  File "/usr/local/lib/python3.11/site-packages/django/db/backends/sqlite3/base.py", line 357, in execute
    return Database.Cursor.execute(self, query, params)

The above exception (database is locked) was the direct cause of the following exception:
  File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 56, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/src/app/nspanelmanager/web/views.py", line 265, in add_light_to_room
    if not Light.objects.filter(room=room, room_view_position=i).exists():
  File "/usr/local/lib/python3.11/site-packages/django/db/models/query.py", line 1226, in exists
    return self.query.has_results(using=self.db)
  File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/query.py", line 592, in has_results
    return compiler.has_results()
  File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 1366, in has_results
    return bool(self.execute_sql(SINGLE))
  File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 1398, in execute_sql
    cursor.execute(sql, params)
  File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 102, in execute
    return super().execute(sql, params)
  File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 67, in execute
    return self._execute_with_wrappers(
  File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 84, in _execute
    with self.db.wrap_database_errors:
  File "/usr/local/lib/python3.11/site-packages/django/db/utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
  File "/usr/local/lib/python3.11/site-packages/django/db/backends/sqlite3/base.py", line 357, in execute
    return Database.Cursor.execute(self, query, params)

Exception Type: OperationalError at /add_light/2
Exception Value: database is locked

Room lights mode + changing kelvin slider

Expected Behavior
If no lights on. Nothing should happen
If 1 or more lights are on only the ones that are on should change

Actual Behavior
When no lights on, both ceiling and table lights turn on
If only ceiling on, table lights turn on as well and vice versa.

Web UI live log on individual panel shows log from other panels?

Not sure what the correct behavior here is but if a panel is set to log level:debug, nothing should be seen in the live log for that panel right?

Right now I'm uploading tft file to 2 panels but all 7 panels live logs is showing the process of tft file upload. Some of them has debug level set to none aswell. Is this correct behavior?

Add ability to use lock function on ceiling/table icon that is off

Current behavior:
Long press on ceiling/table light icon that is OFF and then changing Brightness slider sends no commands to lights.

Enhancement:
Send out commands to light in this situation as well.

Scenario:
User comes home. All lights are off. User wants to start every table lights in the house. Just pressing the brightness dimmer will turn ceiling lights on as well. But this is solved by letting user change to All lights mode, lock table light symbol and then touching the dimmer. MAGIC!

Add choice on physcial buttons for user to send a custom mqtt command

Right now users can choose from Direct mode or Detached mode. There can be users that want to trigger for example their coffee brewer with one of the buttons on just one panel. Add functionality to send a custom mqtt message to allow the user to trigger what ever they want.

Current Kelvin value on panel is not sent out when light goes from OFF > ON

Scenario:

  1. All Table lights in room are ON and at 100% Kelvin
  2. User turns all Table lights in room OFF by pressing table light
  3. User slides kelvin slider on panel to 0%
  4. User turns all Table lights ON by pressing Table lights button.
  5. Lights are turned on but still with 100% Kelvin.

Bug: It seems like Kelvin value is not sent out in this case when a light goes from OFF to ON

Could be only Openhab

Ability to manually unlock lock function

Right now you have to wait for unlock timer before the ceiling/table lock is released.

Suggestion
If table light symbol is in lock mode. Add function to be able to longpress again do unlock.

Situations:
Accidentally entered lock mode.
Superfast user that does not want to wait for it to unlock.

All lights mode not settings lights to the same brightness

Conditions:
Panel in All Lights mode. Lights are on in several rooms and they are set to different percentages.

Current behavior:
When using the brightness slider all Lights that are on does not get the value where the user released the slider. Different values are passed to the lights and very soon after release the slider jumps to a new value.

Expected behavior:
All lights that are on should get the exact same value. The value where the slider was released.

Ability to "wake up" display from users home automation system

User should be able to wake the display up from HA/OH.

For example if a user has movement sensors they might want the display for that room to wake when someone enters the room.
I guess this should be done by having a "Wake Up" topic for each display that user can send a command to from HA/OH.

Light with item type Switch has stopped working

Lights of type Switch does not work. Not from first page or room page.

Error from log:
ERROR:root:Failed to send entity update to OpenHAB. ERROR:root:cannot access local variable 'new_brightness' where it is not associated with a value

Add delete button to room page to be able to remove room

Current behavior:
No ability to delete a room

Enhancement:
Ability to delete room.

Possible solution:
Add one of those cute red delete buttons beside the room on the room page.
All necessary connections to that room should be removed i guess, lights and panels?

Operatonalerror

A little different than previous:

OperationalError at /
database is locked
Request Method:	GET
Request URL:	http://homeassistant.local:8000/
Django Version:	4.1.7
Exception Type:	OperationalError
Exception Value:	
database is locked
Exception Location:	/usr/local/lib/python3.11/site-packages/django/db/backends/sqlite3/base.py, line 357, in execute
Raised during:	web.views.index
Python Executable:	/usr/local/bin/python
Python Version:	3.11.4
Python Path:	
['/usr/src/app/nspanelmanager',
 '/usr/local/lib/python311.zip',
 '/usr/local/lib/python3.11',
 '/usr/local/lib/python3.11/lib-dynload',
 '/usr/local/lib/python3.11/site-packages']
Server time:	Mon, 17 Jul 2023 09:18:25 +0000
Traceback Switch to copy-and-paste view
/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py, line 89, in _execute
                return self.cursor.execute(sql, params) …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/backends/sqlite3/base.py, line 357, in execute
        return Database.Cursor.execute(self, query, params) …
Local vars
The above exception (database is locked) was the direct cause of the following exception:
/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py, line 56, in inner
                response = get_response(request) …
Local vars
/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py, line 197, in _get_response
                response = wrapped_callback(request, *callback_args, **callback_kwargs) …
Local vars
/usr/src/app/nspanelmanager/web/views.py, line 35, in index
    if get_setting_with_default("use_farenheit", False) == "True": …
Local vars
/usr/src/app/nspanelmanager/web/settings_helper.py, line 6, in get_setting_with_default
    if objects.count() > 0: …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/models/query.py, line 621, in count
        return self.query.get_count(using=self.db) …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/models/sql/query.py, line 559, in get_count
        return obj.get_aggregation(using, ["__count"])["__count"] …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/models/sql/query.py, line 544, in get_aggregation
        result = compiler.execute_sql(SINGLE) …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/models/sql/compiler.py, line 1398, in execute_sql
            cursor.execute(sql, params) …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py, line 102, in execute
            return super().execute(sql, params) …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py, line 67, in execute
        return self._execute_with_wrappers( …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py, line 80, in _execute_with_wrappers
        return executor(sql, params, many, context) …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py, line 84, in _execute
        with self.db.wrap_database_errors: …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/utils.py, line 91, in __exit__
                raise dj_exc_value.with_traceback(traceback) from exc_value …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py, line 89, in _execute
                return self.cursor.execute(sql, params) …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/backends/sqlite3/base.py, line 357, in execute
        return Database.Cursor.execute(self, query, params) …
Local vars
Request information
USER
AnonymousUser

GET
No GET data

POST
No POST data

FILES
No FILES data

Variable	Value
csm-hit	
'tb:MHC57C6CAGV1J3GB35Q3+s-V7ZCRKMJN7ZDXC5NGJBR|1680254420832&t:1680254420832&adb:adblk_no'
csrftoken	
'SVBDcuSODqP7ypI9BpTUAVhNjlgbK7Vm'
META
Variable	Value
CONTENT_LENGTH	
''
CONTENT_TYPE	
'text/plain'
CSRF_COOKIE	
'SVBDcuSODqP7ypI9BpTUAVhNjlgbK7Vm'
DJANGO_SETTINGS_MODULE	
'nspanelmanager.settings'
GATEWAY_INTERFACE	
'CGI/1.1'
GPG_KEY	
'********************'
HASSIO_TOKEN	
'********************'
HOME	
'/root'
HOSTNAME	
'local-nspanelmanager'
HTTP_ACCEPT	
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'
HTTP_ACCEPT_ENCODING	
'gzip, deflate'
HTTP_ACCEPT_LANGUAGE	
'en-US,en;q=0.9,et;q=0.8'
HTTP_CACHE_CONTROL	
'max-age=0'
HTTP_CONNECTION	
'keep-alive'
HTTP_COOKIE	
('csm-hit=tb:MHC57C6CAGV1J3GB35Q3+s-V7ZCRKMJN7ZDXC5NGJBR|1680254420832&t:1680254420832&adb:adblk_no; '
 'csrftoken=SVBDcuSODqP7ypI9BpTUAVhNjlgbK7Vm')
HTTP_HOST	
'homeassistant.local:8000'
HTTP_UPGRADE_INSECURE_REQUESTS	
'1'
HTTP_USER_AGENT	
('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, '
 'like Gecko) Chrome/114.0.0.0 Safari/537.36')
IS_HOME_ASSISTANT_ADDON	
'true'
LANG	
'C.UTF-8'
OLDPWD	
'/usr/src/app'
PATH	
'/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
PATH_INFO	
'/'
PWD	
'/usr/src/app/nspanelmanager'
PYTHON_GET_PIP_SHA256	
'96461deced5c2a487ddc65207ec5a9cffeca0d34e7af7ea1afc470ff0d746207'
PYTHON_GET_PIP_URL	
'https://github.com/pypa/get-pip/raw/0d8570dc44796f4369b652222cf176b3db6ac70e/public/get-pip.py'
PYTHON_PIP_VERSION	
'23.1.2'
PYTHON_SETUPTOOLS_VERSION	
'65.5.1'
PYTHON_VERSION	
'3.11.4'
QUERY_STRING	
''
REMOTE_ADDR	
'192.168.1.143'
REMOTE_HOST	
''
REQUEST_METHOD	
'GET'
RUN_MAIN	
'true'
SCRIPT_NAME	
''
SERVER_NAME	
'local-nspanelmanager.local.hass.io'
SERVER_PORT	
'8000'
SERVER_PROTOCOL	
'HTTP/1.1'
SERVER_SOFTWARE	
'WSGIServer/0.2'
SHLVL	
'1'
SUPERVISOR_TOKEN	
'********************'
TZ	
'UTC'
_	
'/usr/local/bin/python'
wsgi.errors	
<_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>
wsgi.file_wrapper	
<class 'wsgiref.util.FileWrapper'>
wsgi.input	
<django.core.handlers.wsgi.LimitedStream object at 0x7f806701d0>
wsgi.multiprocess	
False
wsgi.multithread	
True
wsgi.run_once	
False
wsgi.url_scheme	
'http'
wsgi.version	
(1, 0)
Settings
Using settings module nspanelmanager.settings
Setting	Value
ABSOLUTE_URL_OVERRIDES	
{}
ADMINS	
[]
ALLOWED_HOSTS	
['*']
APPEND_SLASH	
True
AUTHENTICATION_BACKENDS	
['django.contrib.auth.backends.ModelBackend']
AUTH_PASSWORD_VALIDATORS	
'********************'
AUTH_USER_MODEL	
'auth.User'
BASE_DIR	
PosixPath('/usr/src/app/nspanelmanager')
CACHES	
{'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}}
CACHE_MIDDLEWARE_ALIAS	
'default'
CACHE_MIDDLEWARE_KEY_PREFIX	
'********************'
CACHE_MIDDLEWARE_SECONDS	
600
CSRF_COOKIE_AGE	
31449600
CSRF_COOKIE_DOMAIN	
None
CSRF_COOKIE_HTTPONLY	
False
CSRF_COOKIE_MASKED	
False
CSRF_COOKIE_NAME	
'csrftoken'
CSRF_COOKIE_PATH	
'/'
CSRF_COOKIE_SAMESITE	
'Lax'
CSRF_COOKIE_SECURE	
False
CSRF_FAILURE_VIEW	
'django.views.csrf.csrf_failure'
CSRF_HEADER_NAME	
'HTTP_X_CSRFTOKEN'
CSRF_TRUSTED_ORIGINS	
[]
CSRF_USE_SESSIONS	
False
DATABASES	
{'default': {'ATOMIC_REQUESTS': False,
             'AUTOCOMMIT': True,
             'CONN_HEALTH_CHECKS': False,
             'CONN_MAX_AGE': 0,
             'ENGINE': 'django.db.backends.sqlite3',
             'HOST': '',
             'NAME': '/data/nspanelmanager_db.sqlite3',
             'OPTIONS': {},
             'PASSWORD': '********************',
             'PORT': '',
             'TEST': {'CHARSET': None,
                      'COLLATION': None,
                      'MIGRATE': True,
                      'MIRROR': None,
                      'NAME': None},
             'TIME_ZONE': None,
             'USER': ''}}
DATABASE_ROUTERS	
[]
DATA_UPLOAD_MAX_MEMORY_SIZE	
2621440
DATA_UPLOAD_MAX_NUMBER_FIELDS	
1000
DATA_UPLOAD_MAX_NUMBER_FILES	
100
DATETIME_FORMAT	
'N j, Y, P'
DATETIME_INPUT_FORMATS	
['%Y-%m-%d %H:%M:%S',
 '%Y-%m-%d %H:%M:%S.%f',
 '%Y-%m-%d %H:%M',
 '%m/%d/%Y %H:%M:%S',
 '%m/%d/%Y %H:%M:%S.%f',
 '%m/%d/%Y %H:%M',
 '%m/%d/%y %H:%M:%S',
 '%m/%d/%y %H:%M:%S.%f',
 '%m/%d/%y %H:%M']
DATE_FORMAT	
'N j, Y'
DATE_INPUT_FORMATS	
['%Y-%m-%d',
 '%m/%d/%Y',
 '%m/%d/%y',
 '%b %d %Y',
 '%b %d, %Y',
 '%d %b %Y',
 '%d %b, %Y',
 '%B %d %Y',
 '%B %d, %Y',
 '%d %B %Y',
 '%d %B, %Y']
DEBUG	
True
DEBUG_PROPAGATE_EXCEPTIONS	
False
DECIMAL_SEPARATOR	
'.'
DEFAULT_AUTO_FIELD	
'django.db.models.BigAutoField'
DEFAULT_CHARSET	
'utf-8'
DEFAULT_EXCEPTION_REPORTER	
'django.views.debug.ExceptionReporter'
DEFAULT_EXCEPTION_REPORTER_FILTER	
'django.views.debug.SafeExceptionReporterFilter'
DEFAULT_FILE_STORAGE	
'django.core.files.storage.FileSystemStorage'
DEFAULT_FROM_EMAIL	
'webmaster@localhost'
DEFAULT_INDEX_TABLESPACE	
''
DEFAULT_TABLESPACE	
''
DISALLOWED_USER_AGENTS	
[]
EMAIL_BACKEND	
'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST	
'localhost'
EMAIL_HOST_PASSWORD	
'********************'
EMAIL_HOST_USER	
''
EMAIL_PORT	
25
EMAIL_SSL_CERTFILE	
None
EMAIL_SSL_KEYFILE	
'********************'
EMAIL_SUBJECT_PREFIX	
'[Django] '
EMAIL_TIMEOUT	
None
EMAIL_USE_LOCALTIME	
False
EMAIL_USE_SSL	
False
EMAIL_USE_TLS	
False
FILE_UPLOAD_DIRECTORY_PERMISSIONS	
None
FILE_UPLOAD_HANDLERS	
['django.core.files.uploadhandler.MemoryFileUploadHandler',
 'django.core.files.uploadhandler.TemporaryFileUploadHandler']
FILE_UPLOAD_MAX_MEMORY_SIZE	
2621440
FILE_UPLOAD_PERMISSIONS	
420
FILE_UPLOAD_TEMP_DIR	
None
FIRST_DAY_OF_WEEK	
0
FIXTURE_DIRS	
[]
FORCE_SCRIPT_NAME	
None
FORMAT_MODULE_PATH	
None
FORM_RENDERER	
'django.forms.renderers.DjangoTemplates'
IGNORABLE_404_URLS	
[]
INSTALLED_APPS	
['web',
 'mathfilters',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles']
INTERNAL_IPS	
[]
LANGUAGES	
[('af', 'Afrikaans'),
 ('ar', 'Arabic'),
 ('ar-dz', 'Algerian Arabic'),
 ('ast', 'Asturian'),
 ('az', 'Azerbaijani'),
 ('bg', 'Bulgarian'),
 ('be', 'Belarusian'),
 ('bn', 'Bengali'),
 ('br', 'Breton'),
 ('bs', 'Bosnian'),
 ('ca', 'Catalan'),
 ('cs', 'Czech'),
 ('cy', 'Welsh'),
 ('da', 'Danish'),
 ('de', 'German'),
 ('dsb', 'Lower Sorbian'),
 ('el', 'Greek'),
 ('en', 'English'),
 ('en-au', 'Australian English'),
 ('en-gb', 'British English'),
 ('eo', 'Esperanto'),
 ('es', 'Spanish'),
 ('es-ar', 'Argentinian Spanish'),
 ('es-co', 'Colombian Spanish'),
 ('es-mx', 'Mexican Spanish'),
 ('es-ni', 'Nicaraguan Spanish'),
 ('es-ve', 'Venezuelan Spanish'),
 ('et', 'Estonian'),
 ('eu', 'Basque'),
 ('fa', 'Persian'),
 ('fi', 'Finnish'),
 ('fr', 'French'),
 ('fy', 'Frisian'),
 ('ga', 'Irish'),
 ('gd', 'Scottish Gaelic'),
 ('gl', 'Galician'),
 ('he', 'Hebrew'),
 ('hi', 'Hindi'),
 ('hr', 'Croatian'),
 ('hsb', 'Upper Sorbian'),
 ('hu', 'Hungarian'),
 ('hy', 'Armenian'),
 ('ia', 'Interlingua'),
 ('id', 'Indonesian'),
 ('ig', 'Igbo'),
 ('io', 'Ido'),
 ('is', 'Icelandic'),
 ('it', 'Italian'),
 ('ja', 'Japanese'),
 ('ka', 'Georgian'),
 ('kab', 'Kabyle'),
 ('kk', 'Kazakh'),
 ('km', 'Khmer'),
 ('kn', 'Kannada'),
 ('ko', 'Korean'),
 ('ky', 'Kyrgyz'),
 ('lb', 'Luxembourgish'),
 ('lt', 'Lithuanian'),
 ('lv', 'Latvian'),
 ('mk', 'Macedonian'),
 ('ml', 'Malayalam'),
 ('mn', 'Mongolian'),
 ('mr', 'Marathi'),
 ('ms', 'Malay'),
 ('my', 'Burmese'),
 ('nb', 'Norwegian Bokmål'),
 ('ne', 'Nepali'),
 ('nl', 'Dutch'),
 ('nn', 'Norwegian Nynorsk'),
 ('os', 'Ossetic'),
 ('pa', 'Punjabi'),
 ('pl', 'Polish'),
 ('pt', 'Portuguese'),
 ('pt-br', 'Brazilian Portuguese'),
 ('ro', 'Romanian'),
 ('ru', 'Russian'),
 ('sk', 'Slovak'),
 ('sl', 'Slovenian'),
 ('sq', 'Albanian'),
 ('sr', 'Serbian'),
 ('sr-latn', 'Serbian Latin'),
 ('sv', 'Swedish'),
 ('sw', 'Swahili'),
 ('ta', 'Tamil'),
 ('te', 'Telugu'),
 ('tg', 'Tajik'),
 ('th', 'Thai'),
 ('tk', 'Turkmen'),
 ('tr', 'Turkish'),
 ('tt', 'Tatar'),
 ('udm', 'Udmurt'),
 ('uk', 'Ukrainian'),
 ('ur', 'Urdu'),
 ('uz', 'Uzbek'),
 ('vi', 'Vietnamese'),
 ('zh-hans', 'Simplified Chinese'),
 ('zh-hant', 'Traditional Chinese')]
LANGUAGES_BIDI	
['he', 'ar', 'ar-dz', 'fa', 'ur']
LANGUAGE_CODE	
'en-us'
LANGUAGE_COOKIE_AGE	
None
LANGUAGE_COOKIE_DOMAIN	
None
LANGUAGE_COOKIE_HTTPONLY	
False
LANGUAGE_COOKIE_NAME	
'django_language'
LANGUAGE_COOKIE_PATH	
'/'
LANGUAGE_COOKIE_SAMESITE	
None
LANGUAGE_COOKIE_SECURE	
False
LOCALE_PATHS	
[]
LOGGING	
{}
LOGGING_CONFIG	
'logging.config.dictConfig'
LOGIN_REDIRECT_URL	
'/accounts/profile/'
LOGIN_URL	
'/accounts/login/'
LOGOUT_REDIRECT_URL	
None
MANAGERS	
[]
MEDIA_ROOT	
''
MEDIA_URL	
'/'
MESSAGE_STORAGE	
'django.contrib.messages.storage.fallback.FallbackStorage'
MIDDLEWARE	
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']
MIGRATION_MODULES	
{}
MONTH_DAY_FORMAT	
'F j'
NUMBER_GROUPING	
0
PASSWORD_HASHERS	
'********************'
PASSWORD_RESET_TIMEOUT	
'********************'
PREPEND_WWW	
False
ROOT_URLCONF	
'nspanelmanager.urls'
SECRET_KEY	
'********************'
SECRET_KEY_FALLBACKS	
'********************'
SECURE_CONTENT_TYPE_NOSNIFF	
True
SECURE_CROSS_ORIGIN_OPENER_POLICY	
'same-origin'
SECURE_HSTS_INCLUDE_SUBDOMAINS	
False
SECURE_HSTS_PRELOAD	
False
SECURE_HSTS_SECONDS	
0
SECURE_PROXY_SSL_HEADER	
None
SECURE_REDIRECT_EXEMPT	
[]
SECURE_REFERRER_POLICY	
'same-origin'
SECURE_SSL_HOST	
None
SECURE_SSL_REDIRECT	
False
SERVER_EMAIL	
'root@localhost'
SESSION_CACHE_ALIAS	
'default'
SESSION_COOKIE_AGE	
1209600
SESSION_COOKIE_DOMAIN	
None
SESSION_COOKIE_HTTPONLY	
True
SESSION_COOKIE_NAME	
'sessionid'
SESSION_COOKIE_PATH	
'/'
SESSION_COOKIE_SAMESITE	
'Lax'
SESSION_COOKIE_SECURE	
False
SESSION_ENGINE	
'django.contrib.sessions.backends.db'
SESSION_EXPIRE_AT_BROWSER_CLOSE	
False
SESSION_FILE_PATH	
None
SESSION_SAVE_EVERY_REQUEST	
False
SESSION_SERIALIZER	
'django.contrib.sessions.serializers.JSONSerializer'
SETTINGS_MODULE	
'nspanelmanager.settings'
SHORT_DATETIME_FORMAT	
'm/d/Y P'
SHORT_DATE_FORMAT	
'm/d/Y'
SIGNING_BACKEND	
'django.core.signing.TimestampSigner'
SILENCED_SYSTEM_CHECKS	
[]
STATICFILES_DIRS	
[]
STATICFILES_FINDERS	
['django.contrib.staticfiles.finders.FileSystemFinder',
 'django.contrib.staticfiles.finders.AppDirectoriesFinder']
STATICFILES_STORAGE	
'django.contrib.staticfiles.storage.StaticFilesStorage'
STATIC_ROOT	
None
STATIC_URL	
'/static/'
TEMPLATES	
[{'APP_DIRS': True,
  'BACKEND': 'django.template.backends.django.DjangoTemplates',
  'DIRS': [],
  'OPTIONS': {'context_processors': ['django.template.context_processors.debug',
                                     'django.template.context_processors.request',
                                     'django.contrib.auth.context_processors.auth',
                                     'django.contrib.messages.context_processors.messages']}}]
TEST_NON_SERIALIZED_APPS	
[]
TEST_RUNNER	
'django.test.runner.DiscoverRunner'
THOUSAND_SEPARATOR	
','
TIME_FORMAT	
'P'
TIME_INPUT_FORMATS	
['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
TIME_ZONE	
'UTC'
USE_DEPRECATED_PYTZ	
False
USE_I18N	
True
USE_L10N	
True
USE_THOUSAND_SEPARATOR	
False
USE_TZ	
True
USE_X_FORWARDED_HOST	
False
USE_X_FORWARDED_PORT	
False
WSGI_APPLICATION	
'nspanelmanager.wsgi.application'
X_FRAME_OPTIONS	
'DENY'
YEAR_MONTH_FORMAT	
'F Y'
You’re seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard page generated by the handler for this status code.OperationalError at /
database is locked
Request Method:	GET
Request URL:	http://homeassistant.local:8000/
Django Version:	4.1.7
Exception Type:	OperationalError
Exception Value:	
database is locked
Exception Location:	/usr/local/lib/python3.11/site-packages/django/db/backends/sqlite3/base.py, line 357, in execute
Raised during:	web.views.index
Python Executable:	/usr/local/bin/python
Python Version:	3.11.4
Python Path:	
['/usr/src/app/nspanelmanager',
 '/usr/local/lib/python311.zip',
 '/usr/local/lib/python3.11',
 '/usr/local/lib/python3.11/lib-dynload',
 '/usr/local/lib/python3.11/site-packages']
Server time:	Mon, 17 Jul 2023 09:18:25 +0000
Traceback Switch to copy-and-paste view
/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py, line 89, in _execute
                return self.cursor.execute(sql, params) …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/backends/sqlite3/base.py, line 357, in execute
        return Database.Cursor.execute(self, query, params) …
Local vars
The above exception (database is locked) was the direct cause of the following exception:
/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py, line 56, in inner
                response = get_response(request) …
Local vars
/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py, line 197, in _get_response
                response = wrapped_callback(request, *callback_args, **callback_kwargs) …
Local vars
/usr/src/app/nspanelmanager/web/views.py, line 35, in index
    if get_setting_with_default("use_farenheit", False) == "True": …
Local vars
/usr/src/app/nspanelmanager/web/settings_helper.py, line 6, in get_setting_with_default
    if objects.count() > 0: …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/models/query.py, line 621, in count
        return self.query.get_count(using=self.db) …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/models/sql/query.py, line 559, in get_count
        return obj.get_aggregation(using, ["__count"])["__count"] …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/models/sql/query.py, line 544, in get_aggregation
        result = compiler.execute_sql(SINGLE) …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/models/sql/compiler.py, line 1398, in execute_sql
            cursor.execute(sql, params) …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py, line 102, in execute
            return super().execute(sql, params) …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py, line 67, in execute
        return self._execute_with_wrappers( …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py, line 80, in _execute_with_wrappers
        return executor(sql, params, many, context) …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py, line 84, in _execute
        with self.db.wrap_database_errors: …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/utils.py, line 91, in __exit__
                raise dj_exc_value.with_traceback(traceback) from exc_value …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py, line 89, in _execute
                return self.cursor.execute(sql, params) …
Local vars
/usr/local/lib/python3.11/site-packages/django/db/backends/sqlite3/base.py, line 357, in execute
        return Database.Cursor.execute(self, query, params) …
Local vars
Request information
USER
AnonymousUser

GET
No GET data

POST
No POST data

FILES
No FILES data

Variable	Value
csm-hit	
'tb:MHC57C6CAGV1J3GB35Q3+s-V7ZCRKMJN7ZDXC5NGJBR|1680254420832&t:1680254420832&adb:adblk_no'
csrftoken	
'SVBDcuSODqP7ypI9BpTUAVhNjlgbK7Vm'
META
Variable	Value
CONTENT_LENGTH	
''
CONTENT_TYPE	
'text/plain'
CSRF_COOKIE	
'SVBDcuSODqP7ypI9BpTUAVhNjlgbK7Vm'
DJANGO_SETTINGS_MODULE	
'nspanelmanager.settings'
GATEWAY_INTERFACE	
'CGI/1.1'
GPG_KEY	
'********************'
HASSIO_TOKEN	
'********************'
HOME	
'/root'
HOSTNAME	
'local-nspanelmanager'
HTTP_ACCEPT	
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'
HTTP_ACCEPT_ENCODING	
'gzip, deflate'
HTTP_ACCEPT_LANGUAGE	
'en-US,en;q=0.9,et;q=0.8'
HTTP_CACHE_CONTROL	
'max-age=0'
HTTP_CONNECTION	
'keep-alive'
HTTP_COOKIE	
('csm-hit=tb:MHC57C6CAGV1J3GB35Q3+s-V7ZCRKMJN7ZDXC5NGJBR|1680254420832&t:1680254420832&adb:adblk_no; '
 'csrftoken=SVBDcuSODqP7ypI9BpTUAVhNjlgbK7Vm')
HTTP_HOST	
'homeassistant.local:8000'
HTTP_UPGRADE_INSECURE_REQUESTS	
'1'
HTTP_USER_AGENT	
('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, '
 'like Gecko) Chrome/114.0.0.0 Safari/537.36')
IS_HOME_ASSISTANT_ADDON	
'true'
LANG	
'C.UTF-8'
OLDPWD	
'/usr/src/app'
PATH	
'/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
PATH_INFO	
'/'
PWD	
'/usr/src/app/nspanelmanager'
PYTHON_GET_PIP_SHA256	
'96461deced5c2a487ddc65207ec5a9cffeca0d34e7af7ea1afc470ff0d746207'
PYTHON_GET_PIP_URL	
'https://github.com/pypa/get-pip/raw/0d8570dc44796f4369b652222cf176b3db6ac70e/public/get-pip.py'
PYTHON_PIP_VERSION	
'23.1.2'
PYTHON_SETUPTOOLS_VERSION	
'65.5.1'
PYTHON_VERSION	
'3.11.4'
QUERY_STRING	
''
REMOTE_ADDR	
'192.168.1.143'
REMOTE_HOST	
''
REQUEST_METHOD	
'GET'
RUN_MAIN	
'true'
SCRIPT_NAME	
''
SERVER_NAME	
'local-nspanelmanager.local.hass.io'
SERVER_PORT	
'8000'
SERVER_PROTOCOL	
'HTTP/1.1'
SERVER_SOFTWARE	
'WSGIServer/0.2'
SHLVL	
'1'
SUPERVISOR_TOKEN	
'********************'
TZ	
'UTC'
_	
'/usr/local/bin/python'
wsgi.errors	
<_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>
wsgi.file_wrapper	
<class 'wsgiref.util.FileWrapper'>
wsgi.input	
<django.core.handlers.wsgi.LimitedStream object at 0x7f806701d0>
wsgi.multiprocess	
False
wsgi.multithread	
True
wsgi.run_once	
False
wsgi.url_scheme	
'http'
wsgi.version	
(1, 0)
Settings
Using settings module nspanelmanager.settings
Setting	Value
ABSOLUTE_URL_OVERRIDES	
{}
ADMINS	
[]
ALLOWED_HOSTS	
['*']
APPEND_SLASH	
True
AUTHENTICATION_BACKENDS	
['django.contrib.auth.backends.ModelBackend']
AUTH_PASSWORD_VALIDATORS	
'********************'
AUTH_USER_MODEL	
'auth.User'
BASE_DIR	
PosixPath('/usr/src/app/nspanelmanager')
CACHES	
{'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}}
CACHE_MIDDLEWARE_ALIAS	
'default'
CACHE_MIDDLEWARE_KEY_PREFIX	
'********************'
CACHE_MIDDLEWARE_SECONDS	
600
CSRF_COOKIE_AGE	
31449600
CSRF_COOKIE_DOMAIN	
None
CSRF_COOKIE_HTTPONLY	
False
CSRF_COOKIE_MASKED	
False
CSRF_COOKIE_NAME	
'csrftoken'
CSRF_COOKIE_PATH	
'/'
CSRF_COOKIE_SAMESITE	
'Lax'
CSRF_COOKIE_SECURE	
False
CSRF_FAILURE_VIEW	
'django.views.csrf.csrf_failure'
CSRF_HEADER_NAME	
'HTTP_X_CSRFTOKEN'
CSRF_TRUSTED_ORIGINS	
[]
CSRF_USE_SESSIONS	
False
DATABASES	
{'default': {'ATOMIC_REQUESTS': False,
             'AUTOCOMMIT': True,
             'CONN_HEALTH_CHECKS': False,
             'CONN_MAX_AGE': 0,
             'ENGINE': 'django.db.backends.sqlite3',
             'HOST': '',
             'NAME': '/data/nspanelmanager_db.sqlite3',
             'OPTIONS': {},
             'PASSWORD': '********************',
             'PORT': '',
             'TEST': {'CHARSET': None,
                      'COLLATION': None,
                      'MIGRATE': True,
                      'MIRROR': None,
                      'NAME': None},
             'TIME_ZONE': None,
             'USER': ''}}
DATABASE_ROUTERS	
[]
DATA_UPLOAD_MAX_MEMORY_SIZE	
2621440
DATA_UPLOAD_MAX_NUMBER_FIELDS	
1000
DATA_UPLOAD_MAX_NUMBER_FILES	
100
DATETIME_FORMAT	
'N j, Y, P'
DATETIME_INPUT_FORMATS	
['%Y-%m-%d %H:%M:%S',
 '%Y-%m-%d %H:%M:%S.%f',
 '%Y-%m-%d %H:%M',
 '%m/%d/%Y %H:%M:%S',
 '%m/%d/%Y %H:%M:%S.%f',
 '%m/%d/%Y %H:%M',
 '%m/%d/%y %H:%M:%S',
 '%m/%d/%y %H:%M:%S.%f',
 '%m/%d/%y %H:%M']
DATE_FORMAT	
'N j, Y'
DATE_INPUT_FORMATS	
['%Y-%m-%d',
 '%m/%d/%Y',
 '%m/%d/%y',
 '%b %d %Y',
 '%b %d, %Y',
 '%d %b %Y',
 '%d %b, %Y',
 '%B %d %Y',
 '%B %d, %Y',
 '%d %B %Y',
 '%d %B, %Y']
DEBUG	
True
DEBUG_PROPAGATE_EXCEPTIONS	
False
DECIMAL_SEPARATOR	
'.'
DEFAULT_AUTO_FIELD	
'django.db.models.BigAutoField'
DEFAULT_CHARSET	
'utf-8'
DEFAULT_EXCEPTION_REPORTER	
'django.views.debug.ExceptionReporter'
DEFAULT_EXCEPTION_REPORTER_FILTER	
'django.views.debug.SafeExceptionReporterFilter'
DEFAULT_FILE_STORAGE	
'django.core.files.storage.FileSystemStorage'
DEFAULT_FROM_EMAIL	
'webmaster@localhost'
DEFAULT_INDEX_TABLESPACE	
''
DEFAULT_TABLESPACE	
''
DISALLOWED_USER_AGENTS	
[]
EMAIL_BACKEND	
'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST	
'localhost'
EMAIL_HOST_PASSWORD	
'********************'
EMAIL_HOST_USER	
''
EMAIL_PORT	
25
EMAIL_SSL_CERTFILE	
None
EMAIL_SSL_KEYFILE	
'********************'
EMAIL_SUBJECT_PREFIX	
'[Django] '
EMAIL_TIMEOUT	
None
EMAIL_USE_LOCALTIME	
False
EMAIL_USE_SSL	
False
EMAIL_USE_TLS	
False
FILE_UPLOAD_DIRECTORY_PERMISSIONS	
None
FILE_UPLOAD_HANDLERS	
['django.core.files.uploadhandler.MemoryFileUploadHandler',
 'django.core.files.uploadhandler.TemporaryFileUploadHandler']
FILE_UPLOAD_MAX_MEMORY_SIZE	
2621440
FILE_UPLOAD_PERMISSIONS	
420
FILE_UPLOAD_TEMP_DIR	
None
FIRST_DAY_OF_WEEK	
0
FIXTURE_DIRS	
[]
FORCE_SCRIPT_NAME	
None
FORMAT_MODULE_PATH	
None
FORM_RENDERER	
'django.forms.renderers.DjangoTemplates'
IGNORABLE_404_URLS	
[]
INSTALLED_APPS	
['web',
 'mathfilters',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles']
INTERNAL_IPS	
[]
LANGUAGES	
[('af', 'Afrikaans'),
 ('ar', 'Arabic'),
 ('ar-dz', 'Algerian Arabic'),
 ('ast', 'Asturian'),
 ('az', 'Azerbaijani'),
 ('bg', 'Bulgarian'),
 ('be', 'Belarusian'),
 ('bn', 'Bengali'),
 ('br', 'Breton'),
 ('bs', 'Bosnian'),
 ('ca', 'Catalan'),
 ('cs', 'Czech'),
 ('cy', 'Welsh'),
 ('da', 'Danish'),
 ('de', 'German'),
 ('dsb', 'Lower Sorbian'),
 ('el', 'Greek'),
 ('en', 'English'),
 ('en-au', 'Australian English'),
 ('en-gb', 'British English'),
 ('eo', 'Esperanto'),
 ('es', 'Spanish'),
 ('es-ar', 'Argentinian Spanish'),
 ('es-co', 'Colombian Spanish'),
 ('es-mx', 'Mexican Spanish'),
 ('es-ni', 'Nicaraguan Spanish'),
 ('es-ve', 'Venezuelan Spanish'),
 ('et', 'Estonian'),
 ('eu', 'Basque'),
 ('fa', 'Persian'),
 ('fi', 'Finnish'),
 ('fr', 'French'),
 ('fy', 'Frisian'),
 ('ga', 'Irish'),
 ('gd', 'Scottish Gaelic'),
 ('gl', 'Galician'),
 ('he', 'Hebrew'),
 ('hi', 'Hindi'),
 ('hr', 'Croatian'),
 ('hsb', 'Upper Sorbian'),
 ('hu', 'Hungarian'),
 ('hy', 'Armenian'),
 ('ia', 'Interlingua'),
 ('id', 'Indonesian'),
 ('ig', 'Igbo'),
 ('io', 'Ido'),
 ('is', 'Icelandic'),
 ('it', 'Italian'),
 ('ja', 'Japanese'),
 ('ka', 'Georgian'),
 ('kab', 'Kabyle'),
 ('kk', 'Kazakh'),
 ('km', 'Khmer'),
 ('kn', 'Kannada'),
 ('ko', 'Korean'),
 ('ky', 'Kyrgyz'),
 ('lb', 'Luxembourgish'),
 ('lt', 'Lithuanian'),
 ('lv', 'Latvian'),
 ('mk', 'Macedonian'),
 ('ml', 'Malayalam'),
 ('mn', 'Mongolian'),
 ('mr', 'Marathi'),
 ('ms', 'Malay'),
 ('my', 'Burmese'),
 ('nb', 'Norwegian Bokmål'),
 ('ne', 'Nepali'),
 ('nl', 'Dutch'),
 ('nn', 'Norwegian Nynorsk'),
 ('os', 'Ossetic'),
 ('pa', 'Punjabi'),
 ('pl', 'Polish'),
 ('pt', 'Portuguese'),
 ('pt-br', 'Brazilian Portuguese'),
 ('ro', 'Romanian'),
 ('ru', 'Russian'),
 ('sk', 'Slovak'),
 ('sl', 'Slovenian'),
 ('sq', 'Albanian'),
 ('sr', 'Serbian'),
 ('sr-latn', 'Serbian Latin'),
 ('sv', 'Swedish'),
 ('sw', 'Swahili'),
 ('ta', 'Tamil'),
 ('te', 'Telugu'),
 ('tg', 'Tajik'),
 ('th', 'Thai'),
 ('tk', 'Turkmen'),
 ('tr', 'Turkish'),
 ('tt', 'Tatar'),
 ('udm', 'Udmurt'),
 ('uk', 'Ukrainian'),
 ('ur', 'Urdu'),
 ('uz', 'Uzbek'),
 ('vi', 'Vietnamese'),
 ('zh-hans', 'Simplified Chinese'),
 ('zh-hant', 'Traditional Chinese')]
LANGUAGES_BIDI	
['he', 'ar', 'ar-dz', 'fa', 'ur']
LANGUAGE_CODE	
'en-us'
LANGUAGE_COOKIE_AGE	
None
LANGUAGE_COOKIE_DOMAIN	
None
LANGUAGE_COOKIE_HTTPONLY	
False
LANGUAGE_COOKIE_NAME	
'django_language'
LANGUAGE_COOKIE_PATH	
'/'
LANGUAGE_COOKIE_SAMESITE	
None
LANGUAGE_COOKIE_SECURE	
False
LOCALE_PATHS	
[]
LOGGING	
{}
LOGGING_CONFIG	
'logging.config.dictConfig'
LOGIN_REDIRECT_URL	
'/accounts/profile/'
LOGIN_URL	
'/accounts/login/'
LOGOUT_REDIRECT_URL	
None
MANAGERS	
[]
MEDIA_ROOT	
''
MEDIA_URL	
'/'
MESSAGE_STORAGE	
'django.contrib.messages.storage.fallback.FallbackStorage'
MIDDLEWARE	
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']
MIGRATION_MODULES	
{}
MONTH_DAY_FORMAT	
'F j'
NUMBER_GROUPING	
0
PASSWORD_HASHERS	
'********************'
PASSWORD_RESET_TIMEOUT	
'********************'
PREPEND_WWW	
False
ROOT_URLCONF	
'nspanelmanager.urls'
SECRET_KEY	
'********************'
SECRET_KEY_FALLBACKS	
'********************'
SECURE_CONTENT_TYPE_NOSNIFF	
True
SECURE_CROSS_ORIGIN_OPENER_POLICY	
'same-origin'
SECURE_HSTS_INCLUDE_SUBDOMAINS	
False
SECURE_HSTS_PRELOAD	
False
SECURE_HSTS_SECONDS	
0
SECURE_PROXY_SSL_HEADER	
None
SECURE_REDIRECT_EXEMPT	
[]
SECURE_REFERRER_POLICY	
'same-origin'
SECURE_SSL_HOST	
None
SECURE_SSL_REDIRECT	
False
SERVER_EMAIL	
'root@localhost'
SESSION_CACHE_ALIAS	
'default'
SESSION_COOKIE_AGE	
1209600
SESSION_COOKIE_DOMAIN	
None
SESSION_COOKIE_HTTPONLY	
True
SESSION_COOKIE_NAME	
'sessionid'
SESSION_COOKIE_PATH	
'/'
SESSION_COOKIE_SAMESITE	
'Lax'
SESSION_COOKIE_SECURE	
False
SESSION_ENGINE	
'django.contrib.sessions.backends.db'
SESSION_EXPIRE_AT_BROWSER_CLOSE	
False
SESSION_FILE_PATH	
None
SESSION_SAVE_EVERY_REQUEST	
False
SESSION_SERIALIZER	
'django.contrib.sessions.serializers.JSONSerializer'
SETTINGS_MODULE	
'nspanelmanager.settings'
SHORT_DATETIME_FORMAT	
'm/d/Y P'
SHORT_DATE_FORMAT	
'm/d/Y'
SIGNING_BACKEND	
'django.core.signing.TimestampSigner'
SILENCED_SYSTEM_CHECKS	
[]
STATICFILES_DIRS	
[]
STATICFILES_FINDERS	
['django.contrib.staticfiles.finders.FileSystemFinder',
 'django.contrib.staticfiles.finders.AppDirectoriesFinder']
STATICFILES_STORAGE	
'django.contrib.staticfiles.storage.StaticFilesStorage'
STATIC_ROOT	
None
STATIC_URL	
'/static/'
TEMPLATES	
[{'APP_DIRS': True,
  'BACKEND': 'django.template.backends.django.DjangoTemplates',
  'DIRS': [],
  'OPTIONS': {'context_processors': ['django.template.context_processors.debug',
                                     'django.template.context_processors.request',
                                     'django.contrib.auth.context_processors.auth',
                                     'django.contrib.messages.context_processors.messages']}}]
TEST_NON_SERIALIZED_APPS	
[]
TEST_RUNNER	
'django.test.runner.DiscoverRunner'
THOUSAND_SEPARATOR	
','
TIME_FORMAT	
'P'
TIME_INPUT_FORMATS	
['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
TIME_ZONE	
'UTC'
USE_DEPRECATED_PYTZ	
False
USE_I18N	
True
USE_L10N	
True
USE_THOUSAND_SEPARATOR	
False
USE_TZ	
True
USE_X_FORWARDED_HOST	
False
USE_X_FORWARDED_PORT	
False
WSGI_APPLICATION	
'nspanelmanager.wsgi.application'
X_FRAME_OPTIONS	
'DENY'
YEAR_MONTH_FORMAT	
'F Y'
You’re seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard page generated by the handler for this status code.

Update tft file to support possibility to enter both Room Scenes and Home Scenes

There should be a page for both
"Room Scenes" (scenes that saves lights states for lights in a specific room) and
"Home Scenes" (scenes that saves lights states for all lights in the Home).

Task is to decide how the user gets to these pages.
Right now there's a scene button in upper left corner. It could be dependent on if the panel is in Room lights mode or All lights mode.
Or there should be two buttons, one for Room Scenes and one for Home Scenes. Something to think about during Easter holidays...

All lights mode does not work properly

Action:
Pressing button to change from Room Lights mode to All Lights mode.

After this it is only the first ON-press on either table or ceiling lights that have an effect on all lights. OFF press does not work the first time at all.
After this the only lights effected by either OFF or ON press on ceiling or table are the lights in the room that the first page of the panel was on when All Lights mode was entered.

So if having the panels first page set to Bathroom, then entering all lights mode. All lights will turn on on the first press of ceiling or table lights buttons. After that the following ON/OFF presses only effect bathroom lights.

Panel does not seem to go back to Room Lights mode after entering screen saver either.

Implement "Display name" for lights

Implement a "display name" for lights that is shown in the web interface and on the NSPanel. This is so that the light "id" isn't displayed as it can be long and contain a lot of information that is not needed when shown.

NSPanel Manager Scenes Functionality

I think there could be two user solutions for scenes. Number 1 is the primary, nr 2 is nice but personally not a need.

1. For people that don't have scene solutions or think our solution is an easier way of working with scenes.
There should be both Room Scenes and Home Scenes. Room Scenes saves light states for lights in a specific room. Home Scenes saves light states for all lights in the home.

In NSPanel Manager user should be able to name up to 4 room scenes/room and total of 4 home scenes.
These should populate when user accesses the panels room scene page or home scene page which will consist of the scenes, a save button and and activate button.

When pressing save all current lights states in room/home will be saved to NSPanel Manager database.
Pressing On Scene Name will collect the values from database and send it on the HA/OH websocket.

Topic to activate from outside
Scenes created with number 1 solution should have a nice topic so that it is easy to activate the scene from HA/OH (maybe by voice) if user wants that ability.

2. For people who already have scene solutions set up in there smart home that they want to keep using.
In this case the user should be able to call there scenes from the panel. Similar to adding lights to rooms they add there scenes to the scene page. If they have some kind of save switch, the could add this as well and all we would do would be to turn ON/OFF the exposed HA/OH switch.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.