diff --git a/app/content/entities/camera/camera.gd b/app/content/entities/camera/camera.gd index ab4c2b7..ad6401a 100644 --- a/app/content/entities/camera/camera.gd +++ b/app/content/entities/camera/camera.gd @@ -7,11 +7,36 @@ const Entity = preload ("../entity.gd") @onready var view = $View @onready var http_request = $HTTPRequest @onready var mesh = $MeshInstance3D +@onready var refresh_timer = $RefreshTimer +@onready var button = $Button +@onready var slider = $Slider + +var cam_active = R.state(false) +var cam_fps = R.state(10) # Called when the node enters the scene tree for the first time. func _ready(): super() + button.on_button_up.connect(func(): + cam_active.value=!cam_active.value + ) + + R.bind(slider, "value", cam_fps, slider.on_value_changed) + + R.effect(func(_arg): + refresh_timer.wait_time=1.0 / cam_fps.value + ) + + R.effect(func(_arg): + if cam_active.value: + refresh_timer.start() + button.label="videocam" + else: + refresh_timer.stop() + button.label="videocam_off" + ) + icon.value = "photo_camera" var stateInfo = await HomeApi.get_state(entity_id) @@ -23,6 +48,8 @@ func _ready(): ) func set_state(stateInfo): + print("Setting state: ", stateInfo) + if stateInfo == null: view.texture = null mesh.visible = true @@ -36,7 +63,10 @@ func set_state(stateInfo): return if stateInfo["attributes"].has("entity_picture"): - load_image(stateInfo["attributes"]["entity_picture"]) + var url = stateInfo["attributes"]["entity_picture"] + load_image(url) + refresh_timer.timeout.disconnect(load_image.bind(url)) + refresh_timer.timeout.connect(load_image.bind(url)) func load_image(url: String): http_request.request("http://192.168.33.33:8123" + url) @@ -47,15 +77,39 @@ func load_image(url: String): print("Error loading image: ", result[0], " ", result[1]) return - var image = Image.new() - var error = image.load_png_from_buffer(result[3]) + var headers = Array(result[2]).reduce(func(acc, header): + var pair=header.split(":") + acc[pair[0]]=pair[1].trim_prefix(" ").trim_suffix(" ") + return acc + , {}) - var pixel_size = view_width / image.get_size().x + var content_type = headers["Content-Type"] if headers.has("Content-Type") else "image/png" + + var image = Image.new() + var error + + match content_type: + "image/png": + error = image.load_png_from_buffer(result[3]) + "image/jpeg": + error = image.load_jpg_from_buffer(result[3]) + "image/gif": + error = image.load_gif_from_buffer(result[3]) + "image/bmp": + error = image.load_bmp_from_buffer(result[3]) + "image/webp": + error = image.load_webp_from_buffer(result[3]) + _: + print("Unsupported content type: ", content_type, " for image: ", url) + cam_active.value = false + return if error != OK: print("Error loading image: ", error) return + var pixel_size = view_width / image.get_size().x + var texture = ImageTexture.create_from_image(image) view.texture = texture view.pixel_size = pixel_size diff --git a/app/content/entities/camera/camera.tscn b/app/content/entities/camera/camera.tscn index 78545ea..40fea7e 100644 --- a/app/content/entities/camera/camera.tscn +++ b/app/content/entities/camera/camera.tscn @@ -1,7 +1,9 @@ -[gd_scene load_steps=5 format=3 uid="uid://b0nq4wjfckxsa"] +[gd_scene load_steps=7 format=3 uid="uid://b0nq4wjfckxsa"] [ext_resource type="Script" path="res://content/entities/camera/camera.gd" id="1_htxq3"] [ext_resource type="Script" path="res://content/functions/movable.gd" id="2_e2u6o"] +[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="3_8whxu"] +[ext_resource type="PackedScene" uid="uid://pk5k1q8bx0rj" path="res://content/ui/components/slider/slider.tscn" id="4_lfexu"] [sub_resource type="QuadMesh" id="QuadMesh_830bv"] size = Vector2(0.15, 0.15) @@ -26,3 +28,19 @@ shape = SubResource("BoxShape3D_te0pn") [node name="Movable" type="Node" parent="."] script = ExtResource("2_e2u6o") resizable = true + +[node name="RefreshTimer" type="Timer" parent="."] +wait_time = 0.1 + +[node name="Button" parent="." instance=ExtResource("3_8whxu")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.06, -0.1, 0) +label = "videocam_off" +icon = true + +[node name="Slider" parent="." instance=ExtResource("4_lfexu")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.05, -0.1, 0) +min = 1.0 +max = 30.0 +value = 1.0 +step = 1.0 +label_unit = "FPS" diff --git a/app/content/entities/line_chart/line_chart.gd b/app/content/entities/line_chart/line_chart.gd index 911907c..1fb7627 100644 --- a/app/content/entities/line_chart/line_chart.gd +++ b/app/content/entities/line_chart/line_chart.gd @@ -36,6 +36,9 @@ func request_history(): var result = await HomeApi.get_history(entity_id, start) + if result == null: + return + var points = result.data.map(func(point): # Divide by 1000 to convert milliseconds to seconds return Vector2((point.start + point.end) / (2 * 1000), point.mean) diff --git a/app/content/system/dot/dot.gd b/app/content/system/dot/dot.gd index 5a055b7..fb01195 100644 --- a/app/content/system/dot/dot.gd +++ b/app/content/system/dot/dot.gd @@ -7,10 +7,11 @@ const TOUCH_LONG = 400.0 @export var entity: Entity @onready var collision = $CollisionShape3D +@onready var area = $Area3D/CollisionShape3D2 @onready var snap_sound = $SnapSound @onready var label = $Label3D var active = R.state(false) -var disabled = R.state(true) +var disabled = null var touched_enter = 0.0 var moved_ran = false var touch_ran = false @@ -32,6 +33,7 @@ func _ready(): R.effect(func(_arg): visible=!disabled.value collision.disabled=disabled.value + area.disabled=disabled.value ) func _on_click(_event: EventPointer): diff --git a/app/content/system/house/house.gd b/app/content/system/house/house.gd index 90df786..9c2e4df 100644 --- a/app/content/system/house/house.gd +++ b/app/content/system/house/house.gd @@ -24,8 +24,8 @@ func _ready(): func update_house(): loaded.value = false for old_room in get_rooms(0): + old_room.get_parent().remove_child(old_room) old_room.queue_free() - await old_room.tree_exited align_reference.update_align_reference() @@ -101,6 +101,7 @@ func delete_room(room_name): if editing_room == room: editing_room = null + room.get_parent().remove_child(room) room.queue_free() await room.tree_exited diff --git a/app/content/system/house/mini/Entity.gd b/app/content/system/house/mini/Entity.gd index 7f5671a..490e992 100644 --- a/app/content/system/house/mini/Entity.gd +++ b/app/content/system/house/mini/Entity.gd @@ -19,6 +19,7 @@ func _ready(): R.effect(func(_arg): if house_small.value == false||editing.value.size() == 0: if group_entity != null: + remove_child(group_entity) group_entity.queue_free() group_entity=null elif group_entity == null: diff --git a/app/content/system/house/room/states/edit.gd b/app/content/system/house/room/states/edit.gd index b11fb4f..208917f 100644 --- a/app/content/system/house/room/states/edit.gd +++ b/app/content/system/house/room/states/edit.gd @@ -43,18 +43,18 @@ func _on_leave(): update_store() for child in room.wall_corners.get_children(): + room.wall_corners.remove_child(child) child.queue_free() - await child.tree_exited for child in room.wall_edges.get_children(): + room.wall_edges.remove_child(child) child.queue_free() - await child.tree_exited if floor_corner != null: + room.remove_child(floor_corner) floor_corner.queue_free() - await floor_corner.tree_exited + room.remove_child(height_edge) height_edge.queue_free() - await height_edge.tree_exited room.room_ceiling.get_node("CollisionShape3D").disabled = true room.room_floor.get_node("CollisionShape3D").disabled = true diff --git a/app/content/system/trash_bin/trash_bin.gd b/app/content/system/trash_bin/trash_bin.gd index ee9c618..c3c46e5 100644 --- a/app/content/system/trash_bin/trash_bin.gd +++ b/app/content/system/trash_bin/trash_bin.gd @@ -67,6 +67,7 @@ func _ready(): delete_sound.play() for entity in to_delete: + entity.get_parent().remove_child(entity) entity.queue_free() to_delete.clear() trash_bin_large=false diff --git a/app/content/ui/components/slider/slider.gd b/app/content/ui/components/slider/slider.gd index 6984977..a075135 100644 --- a/app/content/ui/components/slider/slider.gd +++ b/app/content/ui/components/slider/slider.gd @@ -58,7 +58,7 @@ func _ready(): _update_slider() _update() - move_plane = Plane(Vector3.UP, Vector3(0, size.y / 200, 0)) + move_plane = Plane(Vector3.BACK, Vector3(0, 0, size.z)) func _on_press_down(event: EventPointer): _handle_press(event) diff --git a/app/lib/globals/event_system.gd b/app/lib/globals/event_system.gd index dbf1747..0c0b67f 100644 --- a/app/lib/globals/event_system.gd +++ b/app/lib/globals/event_system.gd @@ -93,6 +93,9 @@ func _handle_focus(target: Variant, event: EventBubble): if target.is_in_group("ui_focus_stop"): return true + if is_instance_valid(_active_node) == false: + _active_node = null + var event_focus = EventFocus.new() event_focus.previous_target = _active_node event_focus.target = target diff --git a/app/lib/home_apis/hass_ws/handlers/history.gd b/app/lib/home_apis/hass_ws/handlers/history.gd index 5118057..7dcce36 100644 --- a/app/lib/home_apis/hass_ws/handlers/history.gd +++ b/app/lib/home_apis/hass_ws/handlers/history.gd @@ -14,6 +14,9 @@ func get_history(entity_id: String, start: String, end=null): ] }) + if meta_response.status != OK: + return null + var data_response = await api.send_request_packet({ "type": "recorder/statistics_during_period", "start_time": start, @@ -27,6 +30,9 @@ func get_history(entity_id: String, start: String, end=null): ] }) + if data_response.status != OK: + return null + return { "unit": meta_response.payload.result[0]["display_unit_of_measurement"], "has_mean": meta_response.payload.result[0]["has_mean"],