mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-13 14:03:00 +00:00
web ui bug fixes
This commit is contained in:
@@ -1,32 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
Simple script to update files on the Pi
|
|
||||||
"""
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
def copy_file_to_pi(local_file, remote_path):
|
|
||||||
"""Copy a file to the Pi using scp"""
|
|
||||||
try:
|
|
||||||
cmd = ['scp', local_file, f'ledpi@ledpi:{remote_path}']
|
|
||||||
result = subprocess.run(cmd, check=True, capture_output=True, text=True)
|
|
||||||
print(f"Successfully copied {local_file} to {remote_path}")
|
|
||||||
return True
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
print(f"Error copying {local_file}: {e}")
|
|
||||||
print(f"stderr: {e.stderr}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
# Copy the updated web interface file
|
|
||||||
success1 = copy_file_to_pi('web_interface_v2.py', '/home/ledpi/LEDMatrix/')
|
|
||||||
|
|
||||||
# Copy the updated template file
|
|
||||||
success2 = copy_file_to_pi('templates/index_v2.html', '/home/ledpi/LEDMatrix/templates/')
|
|
||||||
|
|
||||||
if success1 and success2:
|
|
||||||
print("All files copied successfully!")
|
|
||||||
print("You can now restart the web interface on the Pi.")
|
|
||||||
else:
|
|
||||||
print("Some files failed to copy. Please check the errors above.")
|
|
||||||
sys.exit(1)
|
|
||||||
@@ -64,60 +64,77 @@ logging.basicConfig(level=logging.INFO)
|
|||||||
|
|
||||||
class DictWrapper:
|
class DictWrapper:
|
||||||
"""Wrapper to make dictionary accessible via dot notation for Jinja2 templates."""
|
"""Wrapper to make dictionary accessible via dot notation for Jinja2 templates."""
|
||||||
def __init__(self, data):
|
def __init__(self, data=None):
|
||||||
|
# Store the original data
|
||||||
|
object.__setattr__(self, '_data', data if isinstance(data, dict) else {})
|
||||||
|
|
||||||
|
# Set attributes from the dictionary
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
for key, value in data.items():
|
for key, value in data.items():
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
setattr(self, key, DictWrapper(value))
|
object.__setattr__(self, key, DictWrapper(value))
|
||||||
|
elif isinstance(value, list):
|
||||||
|
object.__setattr__(self, key, value)
|
||||||
else:
|
else:
|
||||||
setattr(self, key, value)
|
object.__setattr__(self, key, value)
|
||||||
else:
|
|
||||||
# If not a dict, just store the value
|
|
||||||
self._value = data
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
# Return a new DictWrapper with empty dict for missing attributes
|
# Return a new empty DictWrapper for missing attributes
|
||||||
# This allows chaining like main_config.display.hardware.rows
|
# This allows chaining like main_config.display.hardware.rows
|
||||||
return DictWrapper({})
|
return DictWrapper({})
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
# Support bracket notation as fallback
|
# Support bracket notation
|
||||||
return getattr(self, key, DictWrapper({}))
|
return getattr(self, key, DictWrapper({}))
|
||||||
|
|
||||||
def items(self):
|
def items(self):
|
||||||
# Support .items() method for iteration
|
# Support .items() method for iteration
|
||||||
if hasattr(self, '_value'):
|
data = object.__getattribute__(self, '_data')
|
||||||
return {}
|
if data:
|
||||||
return {k: v for k, v in self.__dict__.items() if not k.startswith('_')}
|
return data.items()
|
||||||
|
return {}.items()
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
# Support .get() method
|
# Support .get() method
|
||||||
return getattr(self, key, default)
|
data = object.__getattribute__(self, '_data')
|
||||||
|
if data and key in data:
|
||||||
|
value = data[key]
|
||||||
|
if isinstance(value, dict):
|
||||||
|
return DictWrapper(value)
|
||||||
|
return value
|
||||||
|
return default
|
||||||
|
|
||||||
|
def keys(self):
|
||||||
|
# Support .keys() method
|
||||||
|
data = object.__getattribute__(self, '_data')
|
||||||
|
return data.keys() if data else [].keys()
|
||||||
|
|
||||||
|
def values(self):
|
||||||
|
# Support .values() method
|
||||||
|
data = object.__getattribute__(self, '_data')
|
||||||
|
return data.values() if data else [].values()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
# Return empty string for missing values to avoid template errors
|
# Return empty string for missing values to avoid template errors
|
||||||
if hasattr(self, '_value'):
|
|
||||||
return str(self._value) if self._value is not None else ''
|
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
# Return empty string for missing values
|
# Return empty string for missing values
|
||||||
if hasattr(self, '_value'):
|
|
||||||
return repr(self._value) if self._value is not None else ''
|
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def __html__(self):
|
def __html__(self):
|
||||||
# Support for MarkupSafe HTML escaping
|
# Support for MarkupSafe HTML escaping
|
||||||
return str(self)
|
return ''
|
||||||
|
|
||||||
def __bool__(self):
|
def __bool__(self):
|
||||||
# Return False for empty wrappers
|
# Return False for empty wrappers, True if has data
|
||||||
if hasattr(self, '_value'):
|
data = object.__getattribute__(self, '_data')
|
||||||
# Avoid recursion by checking if _value is a DictWrapper
|
return bool(data)
|
||||||
if isinstance(self._value, DictWrapper):
|
|
||||||
return False # Empty DictWrapper is falsy
|
def __len__(self):
|
||||||
return bool(self._value)
|
# Support len() function
|
||||||
return False
|
data = object.__getattribute__(self, '_data')
|
||||||
|
return len(data) if data else 0
|
||||||
|
|
||||||
class DisplayMonitor:
|
class DisplayMonitor:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -458,7 +475,7 @@ def index():
|
|||||||
|
|
||||||
return render_template('index_v2.html',
|
return render_template('index_v2.html',
|
||||||
schedule_config=schedule_config,
|
schedule_config=schedule_config,
|
||||||
main_config=main_config,
|
main_config=DictWrapper(main_config),
|
||||||
main_config_data=main_config_data,
|
main_config_data=main_config_data,
|
||||||
secrets_config=secrets_config_data,
|
secrets_config=secrets_config_data,
|
||||||
main_config_json=main_config_json,
|
main_config_json=main_config_json,
|
||||||
@@ -475,7 +492,7 @@ def index():
|
|||||||
safe_secrets = {'weather': {'api_key': ''}}
|
safe_secrets = {'weather': {'api_key': ''}}
|
||||||
return render_template('index_v2.html',
|
return render_template('index_v2.html',
|
||||||
schedule_config={},
|
schedule_config={},
|
||||||
main_config={},
|
main_config=DictWrapper({}),
|
||||||
main_config_data={},
|
main_config_data={},
|
||||||
secrets_config=safe_secrets,
|
secrets_config=safe_secrets,
|
||||||
main_config_json="{}",
|
main_config_json="{}",
|
||||||
|
|||||||
Reference in New Issue
Block a user