Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions config/defaults.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@

[preheat PLA]
bed = 60
extruder = 215
extruder = 160
extruder1 = 215

[preheat TPU]
bed = 65
extruder = 225
extruder = 160
extruder1 = 225

[preheat PETG]
bed = 80
extruder = 235
extruder = 160
extruder1 = 235

[preheat ABS]
bed = 110
extruder = 245
extruder = 160
extruder1 = 245

[include main_menu.conf]
Expand Down
10 changes: 5 additions & 5 deletions config/main_menu.conf
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ name: {{ gettext('Update') }}
icon: refresh
panel: updater

# [menu __main more input_shaper]
# name: {{ gettext('Input Shaper') }}
# icon: move
# panel: input_shaper
# enable: {{ 'input_shaper' in printer.config_sections }}
[menu __main more input_shaper]
name: {{ gettext('Input Shaper') }}
icon: move
panel: input_shaper
enable: {{ 'mcu adxl' in printer.config_sections }}

# [menu __main more save]
# name: {{ gettext('Save Config') }}
Expand Down
14 changes: 12 additions & 2 deletions ks_includes/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,13 +162,15 @@ def validate_config(self, config, string="", remove=False):
bools = (
'invert_x', 'invert_y', 'invert_z', '24htime', 'only_heaters', 'show_cursor', 'confirm_estop',
'autoclose_popups', 'use_dpms', 'use_default_menu', 'side_macro_shortcut', 'use-matchbox-keyboard',
'show_heater_power', 'show_lock_button', "show_scroll_steppers", "auto_open_extrude"
'show_heater_power', 'show_lock_button', "show_scroll_steppers", "auto_open_extrude",
'ap_mode_enabled', 'show_ap_toggle'
)
strs = (
'default_printer', 'language', 'print_sort_dir', 'theme', 'screen_blanking_printing', 'font_size',
'print_estimate_method', 'screen_blanking', "screen_on_devices", "screen_off_devices", 'print_view',
"lock_password"
"lock_password", 'ap_ssid', 'ap_password'
)
# Note: ap_mode_enabled is handled as bool but not in configurable_options
numbers = (
'job_complete_timeout', 'job_error_timeout', 'move_speed_xy', 'move_speed_z',
'print_estimate_compensation', 'width', 'height',
Expand Down Expand Up @@ -316,6 +318,14 @@ def _create_configurable_options(self, screen):
{"show_cursor": {"section": "main", "name": _("Show cursor"), "type": "binary",
"tooltip": _("For mouse control or to verify touchscreen accuracy"),
"value": "False", "callback": screen.update_cursor}},
{"show_ap_toggle": {
"section": "main",
"name": _("Show Access Point toggle"),
"type": "binary",
"tooltip": _("Test feature, unstable behavior possible"),
"value": "False",
"callback": screen.reload_panels
}},
# {"": {"section": "main", "name": _(""), "type": ""}}
]

Expand Down
Binary file modified ks_includes/locales/ru/LC_MESSAGES/KlipperScreen.mo
Binary file not shown.
11 changes: 10 additions & 1 deletion ks_includes/locales/ru/LC_MESSAGES/KlipperScreen.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: KlipperScreen\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-26 12:31-0300\n"
"PO-Revision-Date: 2025-12-25 18:27+0300\n"
"PO-Revision-Date: 2026-01-28 17:01+0300\n"
"Last-Translator: gfbdrgng <hnaofegnp@hldrive.com>\n"
"Language-Team: Russian <https://hosted.weblate.org/projects/klipperscreen/klipperscreen/ru/>\n"
"Language: ru\n"
Expand Down Expand Up @@ -237,6 +237,9 @@ msgstr "Прошло:"
msgid "Emergency Stop"
msgstr "Аварийная остановка"

msgid "On/Off auto power off"
msgstr "Вкл/Выкл автовыключение"

msgid "Enable screen power management"
msgstr "Включить панель управление питанием"

Expand Down Expand Up @@ -938,6 +941,12 @@ msgstr "Обновление"
msgid "Show cursor"
msgstr "Отображать курсор"

msgid "Show Access Point toggle"
msgstr "Показывать переключатель точки доступа"

msgid "Test feature, unstable behavior possible"
msgstr "Тестовая функция, возможны сбои"

msgid "For mouse control or to verify touchscreen accuracy"
msgstr "Для управления мышью или для проверки точности сенсора"

Expand Down
151 changes: 147 additions & 4 deletions ks_includes/sdbus_nm.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
# TODO device selection/swtichability
# Alfredo Monclus (alfrix) 2024
import logging
import re
import subprocess
import socket
from uuid import uuid4

import sdbus
Expand Down Expand Up @@ -165,10 +167,15 @@ def is_known(self, ssid):
def get_ip_address(self):
active_connection_path = self.nm.primary_connection
if not active_connection_path or active_connection_path == "/":
return "?"
active_connection = ActiveConnection(active_connection_path)
ip_info = IPv4Config(active_connection.ip4_config)
return ip_info.address_data[0]["address"][1]
# Try to get IP address directly from interface
return self.get_interface_ip_address()
try:
active_connection = ActiveConnection(active_connection_path)
ip_info = IPv4Config(active_connection.ip4_config)
return ip_info.address_data[0]["address"][1]
except Exception as e:
logging.debug(f"Failed to get IP from active connection: {e}")
return self.get_interface_ip_address()

def get_networks(self):
networks = []
Expand Down Expand Up @@ -395,3 +402,139 @@ def monitor_connection_status(self):

def enable_monitoring(self, enable):
self.monitor_connection = enable

def get_interface_ip_address(self):
"""Get IP address directly from network interface"""
try:
interface = self.get_primary_interface()
if not interface:
return "?"
# Try using socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
ip = s.getsockname()[0]
s.close()
return ip
except Exception:
pass
# Fallback to ip command
result = subprocess.run(
["ip", "-4", "addr", "show", interface],
capture_output=True,
text=True,
timeout=2
)
if result.returncode == 0:
match = re.search(r'inet\s+(\d+\.\d+\.\d+\.\d+)', result.stdout)
if match:
return match.group(1)
except Exception as e:
logging.debug(f"Failed to get interface IP: {e}")
return "?"

def is_access_point_mode(self):
"""Check if wireless device is in AP mode"""
if not self.wlan_device:
return False
try:
# Check active connection type
active_connection_path = self.wlan_device.active_connection
if active_connection_path and active_connection_path != "/":
active_connection = ActiveConnection(active_connection_path)
connection_path = active_connection.connection
if connection_path and connection_path != "/":
connection_settings = NetworkConnectionSettings(connection_path)
settings = connection_settings.get_settings()
if "802-11-wireless" in settings:
mode = settings["802-11-wireless"].get("mode", [None, None])[1]
return mode == "ap"
except Exception as e:
logging.debug(f"Failed to check AP mode: {e}")
return False

def get_access_point_connection_path(self):
"""Get connection path for access point if exists"""
try:
saved_network_paths = NetworkManagerSettings().list_connections()
for netpath in saved_network_paths:
saved_con = NetworkConnectionSettings(netpath)
con_settings = saved_con.get_settings()
if (con_settings["connection"]["type"][1] == "802-11-wireless" and
con_settings.get("802-11-wireless", {}).get("mode", [None, None])[1] == "ap"):
return netpath
except Exception as e:
logging.debug(f"Failed to get AP connection path: {e}")
return None

def create_access_point(self, ssid, password):
"""Create and activate access point"""
try:
# Delete existing AP connection if exists
ap_path = self.get_access_point_connection_path()
if ap_path:
NetworkConnectionSettings(ap_path).delete()

# Disconnect current connection
if self.wlan_device.active_connection and self.wlan_device.active_connection != "/":
self.wlan_device.disconnect()

properties: NetworkManagerConnectionProperties = {
"connection": {
"id": ("s", "KlipperScreen-AP"),
"uuid": ("s", str(uuid4())),
"type": ("s", "802-11-wireless"),
"interface-name": ("s", self.wlan_device.interface),
"autoconnect": ("b", True),
},
"802-11-wireless": {
"mode": ("s", "ap"),
"ssid": ("ay", ssid.encode("utf-8")),
"security": ("s", "802-11-wireless-security"),
},
"802-11-wireless-security": {
"key-mgmt": ("s", "wpa-psk"),
"psk": ("s", password),
},
"ipv4": {
"method": ("s", "shared"),
},
"ipv6": {
"method": ("s", "ignore"),
},
}

connection_path = NetworkManagerSettings().add_connection(properties)
logging.info(f"Created AP connection: {connection_path}")

# Activate the connection
self.popup(f"{ssid}\nStarting Access Point", 1)
self.nm.activate_connection(connection_path)
return {"status": "success"}
except exceptions.NmSettingsPermissionDeniedError:
logging.exception("Insufficient privileges")
return {
"error": "insufficient_privileges",
"message": "Insufficient privileges",
}
except Exception as e:
logging.exception("Couldn't create access point")
return {"error": "unknown", "message": "Couldn't create access point" + f"\n{e}"}

def remove_access_point(self):
"""Remove access point and return to normal mode"""
try:
# Disconnect current connection
if self.wlan_device.active_connection and self.wlan_device.active_connection != "/":
self.wlan_device.disconnect()

# Delete AP connection
ap_path = self.get_access_point_connection_path()
if ap_path:
NetworkConnectionSettings(ap_path).delete()
logging.info("Removed AP connection")
return {"status": "success"}
except Exception as e:
logging.exception("Couldn't remove access point")
return {"error": "unknown", "message": "Couldn't remove access point" + f"\n{e}"}
return {"status": "success"}
Loading
Loading