From 09c502eea35fed64635a40607eeb21da73ee472a Mon Sep 17 00:00:00 2001 From: Nitwel Date: Wed, 17 Apr 2024 16:49:58 +0200 Subject: [PATCH 1/6] update entity system, allow batch editing and add entities to mini_view --- app/assets/materials/switch_off.png.import | 14 +-- app/content/entities/button/button.gd | 4 +- app/content/entities/button/button.tscn | 2 +- app/content/entities/camera/camera.gd | 6 +- app/content/entities/camera/camera.tscn | 2 +- app/content/entities/entity.gd | 2 + app/content/entities/light/light.gd | 97 +++++++++++-------- app/content/entities/light/light.tscn | 52 +--------- app/content/entities/light/light_on.tres | 2 - app/content/entities/line_chart/line_chart.gd | 4 +- .../entities/line_chart/line_chart.tscn | 2 +- .../entities/media_player/media_player.gd | 4 + .../entities/media_player/media_player.tscn | 2 +- app/content/entities/number/number.gd | 2 + app/content/entities/number/number.tscn | 2 +- app/content/entities/sensor/sensor.gd | 2 + app/content/entities/sensor/sensor.tscn | 2 +- app/content/entities/switch/switch.gd | 8 +- app/content/entities/switch/switch.tscn | 2 +- app/content/main.gd | 17 +--- .../system/controller_left/controller_left.gd | 14 +-- app/content/system/dot/dot.gd | 38 ++++++++ app/content/system/dot/dot.tscn | 22 +++++ app/content/system/house/house.gd | 4 + app/content/system/house/mini/Entity.gd | 72 ++++++++++++++ app/content/system/house/mini/miniature.gd | 17 ++-- app/content/system/house/mini/miniature.tscn | 15 ++- .../ui/components/line_chart/line_chart.tscn | 4 +- app/content/ui/menu/menu.gd | 39 ++++++-- app/content/ui/menu/menu.tscn | 4 +- app/content/ui/sub_menu/sub_menu.gd | 1 + app/content/ui/sub_menu/sub_menu.tscn | 42 ++++++++ app/lib/globals/home_api.gd | 27 ++++++ app/lib/utils/entity_group.gd | 44 +++++++++ 34 files changed, 415 insertions(+), 156 deletions(-) create mode 100644 app/content/system/dot/dot.gd create mode 100644 app/content/system/dot/dot.tscn create mode 100644 app/content/system/house/mini/Entity.gd create mode 100644 app/content/ui/sub_menu/sub_menu.gd create mode 100644 app/content/ui/sub_menu/sub_menu.tscn create mode 100644 app/lib/utils/entity_group.gd diff --git a/app/assets/materials/switch_off.png.import b/app/assets/materials/switch_off.png.import index bf0fd80..6abed76 100644 --- a/app/assets/materials/switch_off.png.import +++ b/app/assets/materials/switch_off.png.import @@ -3,25 +3,27 @@ importer="texture" type="CompressedTexture2D" uid="uid://co2ishj2hx57p" -path="res://.godot/imported/switch_off.png-c31f6b401a5d3d7cba3c9d0f2c8b28fe.ctex" +path.s3tc="res://.godot/imported/switch_off.png-c31f6b401a5d3d7cba3c9d0f2c8b28fe.s3tc.ctex" +path.etc2="res://.godot/imported/switch_off.png-c31f6b401a5d3d7cba3c9d0f2c8b28fe.etc2.ctex" metadata={ -"vram_texture": false +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true } [deps] source_file="res://assets/materials/switch_off.png" -dest_files=["res://.godot/imported/switch_off.png-c31f6b401a5d3d7cba3c9d0f2c8b28fe.ctex"] +dest_files=["res://.godot/imported/switch_off.png-c31f6b401a5d3d7cba3c9d0f2c8b28fe.s3tc.ctex", "res://.godot/imported/switch_off.png-c31f6b401a5d3d7cba3c9d0f2c8b28fe.etc2.ctex"] [params] -compress/mode=0 +compress/mode=2 compress/high_quality=false compress/lossy_quality=0.7 compress/hdr_compression=1 compress/normal_map=0 compress/channel_pack=0 -mipmaps/generate=false +mipmaps/generate=true mipmaps/limit=-1 roughness/mode=0 roughness/src_normal="" @@ -31,4 +33,4 @@ process/normal_map_invert_y=false process/hdr_as_srgb=false process/hdr_clamp_exposure=false process/size_limit=0 -detect_3d/compress_to=1 +detect_3d/compress_to=0 diff --git a/app/content/entities/button/button.gd b/app/content/entities/button/button.gd index 9e5713b..09b6f93 100644 --- a/app/content/entities/button/button.gd +++ b/app/content/entities/button/button.gd @@ -1,12 +1,14 @@ extends Entity -const Entity = preload("../entity.gd") +const Entity = preload ("../entity.gd") @onready var button = $Button func _ready(): super() + icon.value = "radio_button_checked" + var stateInfo = await HomeApi.get_state(entity_id) if stateInfo == null: diff --git a/app/content/entities/button/button.tscn b/app/content/entities/button/button.tscn index c19ce81..fe04a15 100644 --- a/app/content/entities/button/button.tscn +++ b/app/content/entities/button/button.tscn @@ -8,7 +8,7 @@ [sub_resource type="BoxShape3D" id="BoxShape3D_um5pa"] size = Vector3(0.0700684, 0.011734, 0.0703125) -[node name="Button" type="StaticBody3D" groups=["entity"]] +[node name="Button" type="StaticBody3D" ] script = ExtResource("1_ja7lt") [node name="Button" parent="." instance=ExtResource("1_r4tef")] diff --git a/app/content/entities/camera/camera.gd b/app/content/entities/camera/camera.gd index 1e8b08e..ab4c2b7 100644 --- a/app/content/entities/camera/camera.gd +++ b/app/content/entities/camera/camera.gd @@ -1,6 +1,6 @@ extends Entity -const Entity = preload("../entity.gd") +const Entity = preload ("../entity.gd") @export var view_width = 0.15 @@ -8,11 +8,12 @@ const Entity = preload("../entity.gd") @onready var http_request = $HTTPRequest @onready var mesh = $MeshInstance3D - # Called when the node enters the scene tree for the first time. func _ready(): super() + icon.value = "photo_camera" + var stateInfo = await HomeApi.get_state(entity_id) set_state(stateInfo) @@ -36,7 +37,6 @@ func set_state(stateInfo): if stateInfo["attributes"].has("entity_picture"): load_image(stateInfo["attributes"]["entity_picture"]) - func load_image(url: String): http_request.request("http://192.168.33.33:8123" + url) diff --git a/app/content/entities/camera/camera.tscn b/app/content/entities/camera/camera.tscn index bcfc514..d170230 100644 --- a/app/content/entities/camera/camera.tscn +++ b/app/content/entities/camera/camera.tscn @@ -10,7 +10,7 @@ size = Vector2(0.15, 0.15) [sub_resource type="BoxShape3D" id="BoxShape3D_te0pn"] size = Vector3(0.15, 0.15, 0.01) -[node name="Camera" type="StaticBody3D" groups=["entity"]] +[node name="Camera" type="StaticBody3D" ] script = ExtResource("1_htxq3") [node name="View" type="Sprite3D" parent="."] diff --git a/app/content/entities/entity.gd b/app/content/entities/entity.gd index 04d861d..5735650 100644 --- a/app/content/entities/entity.gd +++ b/app/content/entities/entity.gd @@ -1,6 +1,8 @@ extends StaticBody3D var entity_id: String +var icon = R.state("question_mark") +var icon_color = R.state(Color(1, 1, 1, 1)) func _ready(): var movable = get_node("Movable") diff --git a/app/content/entities/light/light.gd b/app/content/entities/light/light.gd index 11af630..e61366f 100644 --- a/app/content/entities/light/light.gd +++ b/app/content/entities/light/light.gd @@ -1,12 +1,12 @@ extends Entity -const Entity = preload("../entity.gd") -const color_wheel_img := preload("res://assets/canvas.png") +const Entity = preload ("../entity.gd") +const color_wheel_img := preload ("res://assets/canvas.png") @export var color_off = Color(0.23, 0.23, 0.23) @export var color_on = Color(1.0, 0.85, 0.0) -@onready var animation: AnimationPlayer = $AnimationPlayer +@onready var lightbulb = $Lightbulb @onready var slider: Slider3D = $Slider @onready var color_wheel = $ColorWheel @onready var color_puck = $ColorWheel/Puck @@ -17,105 +17,118 @@ const color_wheel_img := preload("res://assets/canvas.png") var state = true var brightness = 0 # 0-255 +var color = color_on +var color_supported = false # Called when the node enters the scene tree for the first time. func _ready(): super() - + + icon.value = "lightbulb" var stateInfo = await HomeApi.get_state(entity_id) - set_state(stateInfo["state"] == "on") + set_state(stateInfo["state"] == "on", stateInfo["attributes"]) - if stateInfo.has("attributes") && stateInfo["attributes"].has("effect_list") && stateInfo["attributes"]["effect_list"].size() > 0: - if stateInfo["attributes"].has("effect") && stateInfo["attributes"]["effect"] != null: + if stateInfo.has("attributes")&&stateInfo["attributes"].has("effect_list")&&stateInfo["attributes"]["effect_list"].size() > 0: + if stateInfo["attributes"].has("effect")&&stateInfo["attributes"]["effect"] != null: mode_label.text = stateInfo["attributes"]["effect"] mode_next.on_button_down.connect(func(): - var index = stateInfo["attributes"]["effect_list"].find(stateInfo["attributes"]["effect"]) - if index == -1: - index = 0 + var index=stateInfo["attributes"]["effect_list"].find(stateInfo["attributes"]["effect"]) + if index == - 1: + index=0 else: - index = (index + 1) % stateInfo["attributes"]["effect_list"].size() + index=(index + 1) % stateInfo["attributes"]["effect_list"].size() - mode_label.text = stateInfo["attributes"]["effect_list"][index] + mode_label.text=stateInfo["attributes"]["effect_list"][index] HomeApi.set_state(entity_id, "on", {"effect": stateInfo["attributes"]["effect_list"][index]}) ) mode_before.on_button_down.connect(func(): - var index = stateInfo["attributes"]["effect_list"].find(stateInfo["attributes"]["effect"]) - if index == -1: - index = 0 + var index=stateInfo["attributes"]["effect_list"].find(stateInfo["attributes"]["effect"]) + if index == - 1: + index=0 else: - index = (index - 1) % stateInfo["attributes"]["effect_list"].size() + index=(index - 1) % stateInfo["attributes"]["effect_list"].size() - mode_label.text = stateInfo["attributes"]["effect_list"][index] + mode_label.text=stateInfo["attributes"]["effect_list"][index] HomeApi.set_state(entity_id, "on", {"effect": stateInfo["attributes"]["effect_list"][index]}) ) else: remove_child(modes) - - if stateInfo.has("attributes") && stateInfo["attributes"].has("supported_color_modes") && stateInfo["attributes"]["supported_color_modes"].has("rgb"): + if stateInfo.has("attributes")&&stateInfo["attributes"].has("supported_color_modes")&&stateInfo["attributes"]["supported_color_modes"].has("rgb"): color_wheel.get_node("Clickable").on_press_down.connect(func(event: EventPointer): - var target_point = color_wheel.to_local(event.ray.get_collision_point()) + var target_point=color_wheel.to_local(event.ray.get_collision_point()) - var delta = Vector2(target_point.x, target_point.z) * (1.0 / 0.08) + var delta=Vector2(target_point.x, target_point.z) * (1.0 / 0.08) if delta.length() > 1: - delta = delta.normalized() + delta=delta.normalized() + + print("delta", delta) - var color = color_wheel_img.get_image().get_pixel((delta.x * 0.5 + 0.5) * 1000, (delta.y * 0.5 + 0.5) * 1000) + var color=color_wheel_img.get_image().get_pixel((delta.x * 0.5 + 0.5) * 1000, (delta.y * 0.5 + 0.5) * 1000) - color_puck.material_override.albedo_color = color - color_puck.position = Vector3(target_point.x, color_puck.position.y, target_point.z) + print("color", color) - var attributes = { + color_puck.material_override.albedo_color=color + color_puck.position=Vector3(target_point.x, color_puck.position.y, target_point.z) + + var attributes={ "rgb_color": [int(color.r * 255), int(color.g * 255), int(color.b * 255)], } HomeApi.set_state(entity_id, "on", attributes) + set_state(state, attributes) ) + color_supported = true else: remove_child(color_wheel) await HomeApi.watch_state(entity_id, func(new_state): if (new_state["state"] == "on") == state: return - set_state(new_state["state"] == "on") + set_state(new_state["state"] == "on", new_state["attributes"]) ) slider.on_value_changed.connect(func(new_value): - var value = new_value / 100 * 255 + var value=new_value / 100 * 255 HomeApi.set_state(entity_id, "on" if state else "off", {"brightness": int(value)}) - set_state(state, value) + set_state(state, {"brightness": value}) ) -func set_state(new_state: bool, new_brightness = null): - if state == false && new_state == false: +func set_state(new_state: bool, attributes={}): + if state == false&&new_state == false: return state = new_state - brightness = new_brightness + + if attributes.has("brightness"): + brightness = attributes["brightness"] + + if attributes.has("rgb_color")&&attributes["rgb_color"] != null: + color = Color(attributes["rgb_color"][0] / 255.0, attributes["rgb_color"][1] / 255.0, attributes["rgb_color"][2] / 255.0, 1) + + var tween = create_tween() + + var target_color = color_off if state: if brightness == null: - animation.speed_scale = 1 - animation.play_backwards("light") + target_color = color if color_supported else color_on else: - var duration = animation.get_animation("light").length - animation.speed_scale = 0 - animation.seek(lerpf(0, duration, 1 - (brightness / 255.0)), true) - else: - animation.speed_scale = 1 - animation.play("light") + target_color = color_off.lerp(color if color_supported else color_on, brightness / 255.0) + icon_color.value = target_color + tween.tween_property(lightbulb, "material_override:albedo_color", target_color, 0.3) func _on_click(event): if event.target == self: var attributes = {} - if !state && brightness != null: + if !state&&brightness != null: attributes["brightness"] = int(brightness) HomeApi.set_state(entity_id, "on" if !state else "off", attributes) - set_state(!state, brightness) + set_state(!state, attributes) diff --git a/app/content/entities/light/light.tscn b/app/content/entities/light/light.tscn index 9296d6e..997a50c 100644 --- a/app/content/entities/light/light.tscn +++ b/app/content/entities/light/light.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=18 format=3 uid="uid://cw86rc42dv2d8"] +[gd_scene load_steps=15 format=3 uid="uid://cw86rc42dv2d8"] [ext_resource type="Script" path="res://content/entities/light/light.gd" id="1_ykxy3"] [ext_resource type="Script" path="res://content/functions/movable.gd" id="4_4sfxb"] @@ -12,43 +12,6 @@ [sub_resource type="SphereShape3D" id="SphereShape3D_ukj14"] radius = 0.05 -[sub_resource type="Animation" id="Animation_afofi"] -length = 0.001 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath("CSGCombiner3D:material_override:albedo_color") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Color(1, 0.85098, 0, 1)] -} - -[sub_resource type="Animation" id="Animation_7o31s"] -resource_name = "light" -length = 0.3 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath("CSGCombiner3D:material_override:albedo_color") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0, 0.3), -"transitions": PackedFloat32Array(1, 1), -"update": 0, -"values": [Color(1, 0.85098, 0, 1), Color(0.231373, 0.231373, 0.231373, 1)] -} - -[sub_resource type="AnimationLibrary" id="AnimationLibrary_8a76q"] -_data = { -"RESET": SubResource("Animation_afofi"), -"light": SubResource("Animation_7o31s") -} - [sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_k3ob2"] points = PackedVector3Array(0, -0.005, -0.08, -0.00784652, -0.005, -0.0796241, 0, 0.005, -0.08, 0.00783085, -0.005, -0.0796241, -0.00784652, 0.005, -0.0796241, -0.0156147, -0.005, -0.0784651, 0.00783085, 0.005, -0.0796241, 0.0155991, -0.005, -0.0784651, -0.0156147, 0.005, -0.0784651, -0.0232263, -0.005, -0.0765701, 0.0155991, 0.005, -0.0784651, 0.0232106, -0.005, -0.0765701, -0.0232263, 0.005, -0.0765701, -0.0306186, -0.005, -0.0739233, 0.0232106, 0.005, -0.0765701, 0.030603, -0.005, -0.0739233, -0.0306186, 0.005, -0.0739233, -0.0377134, -0.005, -0.070556, 0.030603, 0.005, -0.0739233, 0.0376977, -0.005, -0.070556, -0.0377134, 0.005, -0.070556, -0.0444479, -0.005, -0.0665309, 0.0376977, 0.005, -0.070556, 0.0444323, -0.005, -0.0665309, -0.0444479, 0.005, -0.0665309, -0.0507596, -0.005, -0.0618481, 0.0444323, 0.005, -0.0665309, 0.0507439, -0.005, -0.0618481, -0.0507596, 0.005, -0.0618481, -0.0565701, -0.005, -0.0565701, 0.0507439, 0.005, -0.0618481, 0.0565544, -0.005, -0.0565701, -0.0565701, 0.005, -0.0565701, -0.0618481, -0.005, -0.0507596, 0.0565544, 0.005, -0.0565701, 0.0618324, -0.005, -0.0507596, -0.0618481, 0.005, -0.0507596, -0.0665309, -0.005, -0.0444479, 0.0618324, 0.005, -0.0507596, 0.0665153, -0.005, -0.0444479, -0.0665309, 0.005, -0.0444479, -0.070556, -0.005, -0.0377134, 0.0665153, 0.005, -0.0444479, 0.0705403, -0.005, -0.0377134, -0.070556, 0.005, -0.0377134, -0.0739233, -0.005, -0.0306186, 0.0705403, 0.005, -0.0377134, 0.0739076, -0.005, -0.0306186, -0.0739233, 0.005, -0.0306186, -0.0765701, -0.005, -0.0232263, 0.0739076, 0.005, -0.0306186, 0.0765544, -0.005, -0.0232263, -0.0765701, 0.005, -0.0232263, -0.0784651, -0.005, -0.0156147, 0.0765544, 0.005, -0.0232263, 0.0784495, -0.005, -0.0156147, -0.0784651, 0.005, -0.0156147, -0.0796241, -0.005, -0.00784652, 0.0784495, 0.005, -0.0156147, 0.0796085, -0.005, -0.00784652, -0.0796241, 0.005, -0.00784652, -0.08, -0.005, 0, 0.0796085, 0.005, -0.00784652, 0.08, -0.005, 0, -0.08, 0.005, 0, -0.0796241, -0.005, 0.00783085, 0.08, 0.005, 0, 0.0796085, -0.005, 0.00783085, -0.0796241, 0.005, 0.00783085, -0.0784651, -0.005, 0.0155991, 0.0796085, 0.005, 0.00783085, 0.0784495, -0.005, 0.0155991, -0.0784651, 0.005, 0.0155991, -0.0765701, -0.005, 0.0232106, 0.0784495, 0.005, 0.0155991, 0.0765544, -0.005, 0.0232106, -0.0765701, 0.005, 0.0232106, -0.0739233, -0.005, 0.030603, 0.0765544, 0.005, 0.0232106, 0.0739076, -0.005, 0.030603, -0.0739233, 0.005, 0.030603, -0.070556, -0.005, 0.0376977, 0.0739076, 0.005, 0.030603, 0.0705403, -0.005, 0.0376977, -0.070556, 0.005, 0.0376977, -0.0665309, -0.005, 0.0444323, 0.0705403, 0.005, 0.0376977, 0.0665153, -0.005, 0.0444323, -0.0665309, 0.005, 0.0444323, -0.0618481, -0.005, 0.0507439, 0.0665153, 0.005, 0.0444323, 0.0618324, -0.005, 0.0507439, -0.0618481, 0.005, 0.0507439, -0.0565701, -0.005, 0.0565544, 0.0618324, 0.005, 0.0507439, 0.0565544, -0.005, 0.0565544, -0.0565701, 0.005, 0.0565544, -0.0507596, -0.005, 0.0618324, 0.0565544, 0.005, 0.0565544, 0.0507439, -0.005, 0.0618324, -0.0507596, 0.005, 0.0618324, -0.0444479, -0.005, 0.0665153, 0.0507439, 0.005, 0.0618324, 0.0444323, -0.005, 0.0665153, -0.0444479, 0.005, 0.0665153, -0.0377134, -0.005, 0.0705403, 0.0444323, 0.005, 0.0665153, 0.0376977, -0.005, 0.0705403, -0.0377134, 0.005, 0.0705403, -0.0306186, -0.005, 0.0739076, 0.0376977, 0.005, 0.0705403, 0.030603, -0.005, 0.0739076, -0.0306186, 0.005, 0.0739076, -0.0232263, -0.005, 0.0765544, 0.030603, 0.005, 0.0739076, 0.0232106, -0.005, 0.0765544, -0.0232263, 0.005, 0.0765544, -0.0156147, -0.005, 0.0784495, 0.0232106, 0.005, 0.0765544, 0.0155991, -0.005, 0.0784495, -0.0156147, 0.005, 0.0784495, -0.00784652, -0.005, 0.0796085, 0.0155991, 0.005, 0.0784495, 0.00783085, -0.005, 0.0796085, -0.00784652, 0.005, 0.0796085, 0, -0.005, 0.08, 0.00783085, 0.005, 0.0796085, 0, 0.005, 0.08) @@ -67,7 +30,7 @@ top_radius = 0.01 bottom_radius = 0.01 height = 0.005 -[node name="Light" type="StaticBody3D" groups=["entity"]] +[node name="Light" type="StaticBody3D"] collision_mask = 0 script = ExtResource("1_ykxy3") @@ -80,26 +43,21 @@ script = ExtResource("5_oh4jg") [node name="Movable" type="Node" parent="."] script = ExtResource("4_4sfxb") -[node name="CSGCombiner3D" type="CSGCombiner3D" parent="."] +[node name="Lightbulb" type="CSGCombiner3D" parent="."] transform = Transform3D(1, 9.69949e-05, 0.000589194, -9.77749e-05, 0.999999, 0.00135802, -0.000589065, -0.00135808, 0.999999, 0, 0, 0) material_override = ExtResource("5_50gph") -[node name="CSGSphere3D" type="CSGSphere3D" parent="CSGCombiner3D"] +[node name="CSGSphere3D" type="CSGSphere3D" parent="Lightbulb"] radius = 0.05 radial_segments = 36 rings = 12 -[node name="CSGCylinder3D" type="CSGCylinder3D" parent="CSGCombiner3D"] +[node name="CSGCylinder3D" type="CSGCylinder3D" parent="Lightbulb"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.0485739, 0) radius = 0.02 height = 0.03 sides = 36 -[node name="AnimationPlayer" type="AnimationPlayer" parent="."] -libraries = { -"": SubResource("AnimationLibrary_8a76q") -} - [node name="Slider" parent="." instance=ExtResource("6_mhjlm")] transform = Transform3D(1.91069e-15, 4.37114e-08, 1, 1, -4.37114e-08, 0, 4.37114e-08, 1, -4.37114e-08, 0.08, 0, 0) max = 100.0 diff --git a/app/content/entities/light/light_on.tres b/app/content/entities/light/light_on.tres index 4b8aebe..e590915 100644 --- a/app/content/entities/light/light_on.tres +++ b/app/content/entities/light/light_on.tres @@ -2,7 +2,5 @@ [resource] resource_local_to_scene = true -albedo_color = Color(1, 0.85098, 0, 1) -emission_enabled = true emission = Color(1, 0.65098, 0, 1) emission_energy_multiplier = 0.0 diff --git a/app/content/entities/line_chart/line_chart.gd b/app/content/entities/line_chart/line_chart.gd index b8c8083..911907c 100644 --- a/app/content/entities/line_chart/line_chart.gd +++ b/app/content/entities/line_chart/line_chart.gd @@ -9,6 +9,8 @@ const Entity = preload ("../entity.gd") func _ready(): super() + icon.value = "finance" + label.text = entity_id if HomeApi.has_connected() == false: @@ -43,4 +45,4 @@ func request_history(): line_chart.y_axis_label.value = result.unit func get_interface(): - return "line_chart" \ No newline at end of file + return "line_chart" diff --git a/app/content/entities/line_chart/line_chart.tscn b/app/content/entities/line_chart/line_chart.tscn index 0c05b7c..8470b43 100644 --- a/app/content/entities/line_chart/line_chart.tscn +++ b/app/content/entities/line_chart/line_chart.tscn @@ -7,7 +7,7 @@ [sub_resource type="BoxShape3D" id="BoxShape3D_rmm5v"] size = Vector3(0.5, 0.3, 0.001) -[node name="LineChart" type="StaticBody3D" groups=["entity"]] +[node name="LineChart" type="StaticBody3D"] collision_layer = 5 collision_mask = 0 script = ExtResource("1_5dxim") diff --git a/app/content/entities/media_player/media_player.gd b/app/content/entities/media_player/media_player.gd index 9889732..ffc59d1 100644 --- a/app/content/entities/media_player/media_player.gd +++ b/app/content/entities/media_player/media_player.gd @@ -20,6 +20,8 @@ var volume = 50 func _ready(): super() + icon.value = "pause_circle" + var stateInfo = await HomeApi.get_state(entity_id) set_state(stateInfo) @@ -65,9 +67,11 @@ func set_state(stateInfo): playing = true play.label = "pause" + icon.value = "play_circle" else: playing = false play.label = "play_arrow" + icon.value = "pause_circle" func load_image(url: String): http_request.request("http://192.168.33.33:8123" + url) diff --git a/app/content/entities/media_player/media_player.tscn b/app/content/entities/media_player/media_player.tscn index aad010a..248a968 100644 --- a/app/content/entities/media_player/media_player.tscn +++ b/app/content/entities/media_player/media_player.tscn @@ -10,7 +10,7 @@ [sub_resource type="BoxShape3D" id="BoxShape3D_vi3eg"] size = Vector3(0.23, 0.142768, 0.01) -[node name="MediaPlayer" type="StaticBody3D" groups=["entity"]] +[node name="MediaPlayer" type="StaticBody3D" ] collision_mask = 0 script = ExtResource("1_ame17") diff --git a/app/content/entities/number/number.gd b/app/content/entities/number/number.gd index b282a25..89c3ea7 100644 --- a/app/content/entities/number/number.gd +++ b/app/content/entities/number/number.gd @@ -8,6 +8,8 @@ const Entity = preload ("../entity.gd") func _ready(): super() + icon.value = "sliders" + var stateInfo = await HomeApi.get_state(entity_id) if stateInfo == null: return diff --git a/app/content/entities/number/number.tscn b/app/content/entities/number/number.tscn index f8dba61..62ded9f 100644 --- a/app/content/entities/number/number.tscn +++ b/app/content/entities/number/number.tscn @@ -8,7 +8,7 @@ [sub_resource type="BoxShape3D" id="BoxShape3D_7mk8w"] size = Vector3(0.0390625, 0.114258, 0.0142822) -[node name="Number" type="StaticBody3D" groups=["entity"]] +[node name="Number" type="StaticBody3D" ] script = ExtResource("1_26xwp") [node name="Slider" parent="." instance=ExtResource("2_sninv")] diff --git a/app/content/entities/sensor/sensor.gd b/app/content/entities/sensor/sensor.gd index 5f3f1c9..6d2a760 100644 --- a/app/content/entities/sensor/sensor.gd +++ b/app/content/entities/sensor/sensor.gd @@ -14,6 +14,8 @@ var is_text = true func _ready(): super() + icon.value = "sensors" + var stateInfo = await HomeApi.get_state(entity_id) set_text(stateInfo) diff --git a/app/content/entities/sensor/sensor.tscn b/app/content/entities/sensor/sensor.tscn index 65f1118..ecc94cd 100644 --- a/app/content/entities/sensor/sensor.tscn +++ b/app/content/entities/sensor/sensor.tscn @@ -10,7 +10,7 @@ resource_local_to_scene = true size = Vector3(0.18, 0.03, 0.02) -[node name="Sensor" type="StaticBody3D" groups=["entity"]] +[node name="Sensor" type="StaticBody3D" ] collision_mask = 0 script = ExtResource("1_57ac8") diff --git a/app/content/entities/switch/switch.gd b/app/content/entities/switch/switch.gd index f91098b..4cb1b19 100644 --- a/app/content/entities/switch/switch.gd +++ b/app/content/entities/switch/switch.gd @@ -1,13 +1,12 @@ extends Entity -const Entity = preload("../entity.gd") +const Entity = preload ("../entity.gd") @onready var sprite: AnimatedSprite3D = $Icon # Called when the node enters the scene tree for the first time. func _ready(): super() - var stateInfo = await HomeApi.get_state(entity_id) if stateInfo == null: return @@ -17,13 +16,16 @@ func _ready(): else: sprite.set_frame(1) + icon.value = "toggle_" + stateInfo["state"] + await HomeApi.watch_state(entity_id, func(new_state): if new_state["state"] == "on": sprite.set_frame(0) else: sprite.set_frame(1) - ) + icon.value="toggle_" + new_state["state"] + ) func _on_click(event): HomeApi.set_state(entity_id, "off" if sprite.get_frame() == 0 else "on") diff --git a/app/content/entities/switch/switch.tscn b/app/content/entities/switch/switch.tscn index e0e0589..0fbeddc 100644 --- a/app/content/entities/switch/switch.tscn +++ b/app/content/entities/switch/switch.tscn @@ -23,7 +23,7 @@ animations = [{ "speed": 5.0 }] -[node name="Switch" type="StaticBody3D" groups=["entity"]] +[node name="Switch" type="StaticBody3D" ] collision_mask = 0 script = ExtResource("1_8ffhi") diff --git a/app/content/main.gd b/app/content/main.gd index 86af213..0746948 100644 --- a/app/content/main.gd +++ b/app/content/main.gd @@ -40,7 +40,6 @@ func _ready(): _emit_action(name, false, true) ) - remove_child(menu) remove_child(keyboard) EventSystem.on_action_down.connect(func(action): @@ -81,13 +80,7 @@ func create_voice_assistant(): ) func toggle_menu(): - if menu.show_menu == false: - add_child(menu) - menu.global_transform = _get_menu_transform() - menu.show_menu = !menu.show_menu - await menu.get_node("AnimationPlayer").animation_finished - if menu.show_menu == false: - remove_child(menu) + menu.show_menu.value = !menu.show_menu.value func _emit_action(name: String, value, right_controller: bool=true): var event = EventAction.new() @@ -126,14 +119,6 @@ func _input(event): if event is InputEventKey and Input.is_key_pressed(KEY_M): toggle_menu() -func _get_menu_transform(): - var transform = camera.get_global_transform() - transform.origin -= transform.basis.z * 0.5 - - transform.basis = transform.basis.rotated(transform.basis.x, deg_to_rad(90)) - - return transform - func vector_key_mapping(key_positive_x: int, key_negative_x: int, key_positive_y: int, key_negative_y: int): var x = 0 var y = 0 diff --git a/app/content/system/controller_left/controller_left.gd b/app/content/system/controller_left/controller_left.gd index ad5b344..4db2e50 100644 --- a/app/content/system/controller_left/controller_left.gd +++ b/app/content/system/controller_left/controller_left.gd @@ -1,5 +1,7 @@ extends XRController3D +const Entity = preload ("res://content/entities/entity.gd") + @onready var area = $trash_bin/Area3D @onready var trash_bin = $trash_bin @onready var animation = $AnimationPlayer @@ -35,21 +37,21 @@ func _ready(): trash_bin_visible = false EventSystem.on_grab_down.connect(func(event: EventPointer): - trash_bin_visible = event.target.is_in_group("entity") + trash_bin_visible=event.target is Entity ) EventSystem.on_grab_move.connect(func(event): if !trash_bin_visible: return - if event.target.is_in_group("entity") && area.overlaps_body(event.target): + if event.target is Entity&&area.overlaps_body(event.target): if !to_delete.has(event.target): to_delete.append(event.target) - trash_bin_large = true + trash_bin_large=true else: to_delete.erase(event.target) - trash_bin_large = false + trash_bin_large=false ) @@ -60,6 +62,6 @@ func _ready(): for entity in to_delete: entity.queue_free() to_delete.clear() - trash_bin_large = false - trash_bin_visible = false + trash_bin_large=false + trash_bin_visible=false ) diff --git a/app/content/system/dot/dot.gd b/app/content/system/dot/dot.gd new file mode 100644 index 0000000..8ed2ad4 --- /dev/null +++ b/app/content/system/dot/dot.gd @@ -0,0 +1,38 @@ +extends StaticBody3D + +const Entity = preload ("res://content/entities/entity.gd") + +@export var entity: Entity + +@onready var collision = $CollisionShape3D +@onready var label = $Label3D +var active = R.state(false) +var disabled = R.state(true) + +var miniature = House.body.mini_view + +func _ready(): + R.effect(func(_arg): + label.text=entity.icon.value + label.modulate=entity.icon_color.value + ) + + # Update active + R.effect(func(_arg): + label.outline_modulate=Color(242, 90, 56, 1) if active.value else Color(0, 0, 0, 1) + ) + + # Update disabled + R.effect(func(_arg): + visible=!disabled.value + collision.disabled=disabled.value + ) + +func _on_click(_event: EventPointer): + if entity.has_method("quick_action"): + entity.quick_action() + else: + miniature.entity_select.toggle(entity) + +func _on_move_start(_event: EventPointer): + miniature.entity_select.toggle(entity) \ No newline at end of file diff --git a/app/content/system/dot/dot.tscn b/app/content/system/dot/dot.tscn new file mode 100644 index 0000000..4e1901b --- /dev/null +++ b/app/content/system/dot/dot.tscn @@ -0,0 +1,22 @@ +[gd_scene load_steps=4 format=3 uid="uid://b5buw1sas18n4"] + +[ext_resource type="Script" path="res://content/system/dot/dot.gd" id="1_vdpux"] +[ext_resource type="FontVariation" uid="uid://sshfnckriqxn" path="res://assets/icons/icons.tres" id="4_504vw"] + +[sub_resource type="SphereShape3D" id="SphereShape3D_3wgjq"] +custom_solver_bias = 0.2 +radius = 0.1 + +[node name="Dot" type="StaticBody3D"] +script = ExtResource("1_vdpux") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +shape = SubResource("SphereShape3D_3wgjq") + +[node name="Label3D" type="Label3D" parent="."] +pixel_size = 0.002 +billboard = 1 +text = "lightbulb" +font = ExtResource("4_504vw") +font_size = 100 +outline_size = 18 diff --git a/app/content/system/house/house.gd b/app/content/system/house/house.gd index acaa35f..92d1053 100644 --- a/app/content/system/house/house.gd +++ b/app/content/system/house/house.gd @@ -12,6 +12,7 @@ const AlignReference = preload ("./align_reference.gd") var fixing_reference: bool = false var editing_room: RoomType = null +var loaded = R.state(false) func _ready(): Store.house.on_loaded.connect(func(): @@ -19,6 +20,7 @@ func _ready(): ) func update_house(): + loaded.value = false for old_room in get_rooms(0): old_room.queue_free() await old_room.tree_exited @@ -46,6 +48,8 @@ func update_house(): entity_instance.global_position = entity.position entity_instance.global_rotation = entity.rotation + loaded.value = true + func create_room(room_name: String, level: int) -> RoomType: var existing_room = Store.house.get_room(room_name) diff --git a/app/content/system/house/mini/Entity.gd b/app/content/system/house/mini/Entity.gd new file mode 100644 index 0000000..d7341f6 --- /dev/null +++ b/app/content/system/house/mini/Entity.gd @@ -0,0 +1,72 @@ +extends Marker3D + +const DotScene = preload ("res://content/system/dot/dot.tscn") +const Entity = preload ("res://content/entities/entity.gd") + +@onready var dots = $"../Small/Dots" + +var active_type = null +var editing = R.state([]) +var group_entity = null + +func _ready(): + await House.body.ready + + # Update Group Entity + R.effect(func(_arg): + if editing.value.size() == 0: + if group_entity != null: + group_entity.queue_free() + group_entity=null + elif group_entity == null: + print(editing.value.map(func(entity): return entity.entity_id)) + var id=HomeApi.groups.create(editing.value.map(func(entity): return entity.entity_id)) + group_entity=EntityFactory.create_entity(id, active_type) + add_child(group_entity) + else: + HomeApi.groups.update_entities(group_entity.entity_id, editing.value.map(func(entity): return entity.entity_id)) + ) + + var dots_disabled = R.computed(func(_arg): + return House.body.mini_view.small.value == false + ) + + # Update Entities + R.effect(func(_arg): + if House.body.loaded.value == false: + return + + if Store.house.state.entities.size() == 0: + return + + for old_dot in dots.get_children(): + dots.remove_child(old_dot) + old_dot.free() + + for room in House.body.get_rooms(0): + for entity in room.get_node("Entities").get_children(): + var dot=DotScene.instantiate() + + dot.position=House.body.to_local(entity.global_position) + dot.entity=entity + dot.active=R.computed(func(_arg2): + return editing.value.has(entity) + ) + dot.disabled=dots_disabled + dots.add_child(dot) + ) + +func toggle(entity: Entity): + if active_type == null: + active_type = entity.entity_id.split(".")[0] + elif active_type != entity.entity_id.split(".")[0]: + return + + if editing.value.has(entity): + editing.value.erase(entity) + if editing.value.size() == 0: + active_type = null + else: + editing.value.append(entity) + + editing.value = editing.value diff --git a/app/content/system/house/mini/miniature.gd b/app/content/system/house/mini/miniature.gd index 688e2fe..9dccb84 100644 --- a/app/content/system/house/mini/miniature.gd +++ b/app/content/system/house/mini/miniature.gd @@ -2,14 +2,15 @@ extends Node3D const ConstructRoomMesh = preload ("res://lib/utils/mesh/construct_room_mesh.gd") const wall_material = preload ("./mini_wall.tres") - const humidity_gradient = preload ("./humid_gradient.tres") const temperature_gradient = preload ("./temp_gradient.tres") @onready var body = $Body -@onready var model = $Body/Model +@onready var small_node = $Body/Small +@onready var model = $Body/Small/Model @onready var collision_shape = $Body/CollisionShape3D @onready var toggle_heatmap = $Body/HeatmapButton +@onready var entity_select = $Body/EntitySelect enum HeatmapType { NONE = 0, @@ -75,12 +76,15 @@ func _ready(): if small.value: var aabb=House.body.get_level_aabb(0) + var height=aabb.size.y + aabb.position.y=- 0.03 aabb.size.y=0.06 var center=aabb.position + aabb.size / 2 collision_shape.shape.size=aabb.size * 0.1 + entity_select.position=Vector3(0, height * 0.1 + 0.1, 0) var camera=$"/root/Main/XROrigin3D/XRCamera3D" var camera_position=camera.global_position @@ -92,10 +96,10 @@ func _ready(): var target_position=camera_position + camera_direction.normalized() * 0.2 var new_position=target_position - center * 0.1 - tween.tween_property(model, "scale", Vector3(0.1, 0.1, 0.1), 0.5) + tween.tween_property(small_node, "scale", Vector3(0.1, 0.1, 0.1), 0.5) tween.tween_property(body, "position", new_position, 0.5) else: - tween.tween_property(model, "scale", Vector3.ONE, 0.5) + tween.tween_property(small_node, "scale", Vector3.ONE, 0.5) tween.tween_property(body, "position", Vector3.ZERO, 0.5) tween.tween_property(body, "quaternion", Quaternion.IDENTITY, 0.5) ) @@ -104,9 +108,8 @@ func _ready(): R.effect(func(_arg): var show_map=heatmap_type.value != HeatmapType.NONE var show_small=small.value - - for child in model.get_children(): - child.visible=show_map||show_small + + model.visible=show_map||show_small ) # Update Heatmap diff --git a/app/content/system/house/mini/miniature.tscn b/app/content/system/house/mini/miniature.tscn index 885837a..be396af 100644 --- a/app/content/system/house/mini/miniature.tscn +++ b/app/content/system/house/mini/miniature.tscn @@ -1,7 +1,8 @@ -[gd_scene load_steps=4 format=3 uid="uid://ds60i5n211hi3"] +[gd_scene load_steps=5 format=3 uid="uid://ds60i5n211hi3"] [ext_resource type="Script" path="res://content/system/house/mini/miniature.gd" id="1_b53yn"] [ext_resource type="Script" path="res://content/functions/movable.gd" id="2_x7oed"] +[ext_resource type="Script" path="res://content/system/house/mini/Entity.gd" id="3_tgpny"] [sub_resource type="BoxShape3D" id="BoxShape3D_bckw3"] @@ -15,5 +16,15 @@ shape = SubResource("BoxShape3D_bckw3") [node name="Movable" type="Node" parent="Body"] script = ExtResource("2_x7oed") +restricted = true -[node name="Model" type="Node3D" parent="Body"] +[node name="Small" type="Node3D" parent="Body"] + +[node name="Model" type="Node3D" parent="Body/Small"] + +[node name="Dots" type="Node3D" parent="Body/Small"] + +[node name="EntitySelect" type="Marker3D" parent="Body"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.757576, 0) +gizmo_extents = 0.1 +script = ExtResource("3_tgpny") diff --git a/app/content/ui/components/line_chart/line_chart.tscn b/app/content/ui/components/line_chart/line_chart.tscn index 6cf4679..22721d6 100644 --- a/app/content/ui/components/line_chart/line_chart.tscn +++ b/app/content/ui/components/line_chart/line_chart.tscn @@ -10,7 +10,7 @@ cull_mode = 2 shading_mode = 0 albedo_color = Color(0.109804, 0.721569, 0.262745, 1) -[sub_resource type="ArrayMesh" id="ArrayMesh_raxtd"] +[sub_resource type="ArrayMesh" id="ArrayMesh_25da5"] _surfaces = [{ "aabb": AABB(-0.000587015, -0.000596339, 0.0005, 0.501171, 0.301189, 1e-05), "format": 34359742465, @@ -43,7 +43,7 @@ script = ExtResource("1_n7fu8") [node name="Line" type="MeshInstance3D" parent="."] material_override = SubResource("StandardMaterial3D_20gpn") -mesh = SubResource("ArrayMesh_raxtd") +mesh = SubResource("ArrayMesh_25da5") [node name="Plane" type="MeshInstance3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.25, 0.15, -0.001) diff --git a/app/content/ui/menu/menu.gd b/app/content/ui/menu/menu.gd index 90642d9..59afcc2 100644 --- a/app/content/ui/menu/menu.gd +++ b/app/content/ui/menu/menu.gd @@ -1,28 +1,49 @@ extends Node3D -const Notification = preload("res://content/ui/components/notification/notification.tscn") +const Notification = preload ("res://content/ui/components/notification/notification.tscn") @onready var animation_player = $AnimationPlayer @onready var notify_place = $AnimationContainer/NotifyPlace +@onready var main = $"/root/Main" -var show_menu := false: - set(value): - show_menu = value - if value: +var show_menu = R.state(false) + +func _ready(): + await main.ready + + main.remove_child(self) + + R.effect(func(_arg): + if show_menu.value: + main.add_child(self) + move_into_view() animation_player.play_backwards("hide_menu") AudioPlayer.play_effect("open_menu") else: animation_player.play("hide_menu") AudioPlayer.play_effect("close_menu") + ) + + animation_player.animation_finished.connect(func(_animation): + if show_menu.value == false: + main.remove_child(self) + ) -func _ready(): EventSystem.on_notify.connect(func(event: EventNotify): - var notification_node = Notification.instantiate() - notification_node.text = event.message - notification_node.type = event.type + var notification_node=Notification.instantiate() + notification_node.text=event.message + notification_node.type=event.type for child in notify_place.get_children(): child.position += Vector3(0, 0, -0.06) notify_place.add_child(notification_node) ) + +func move_into_view(): + var camera_transform = main.camera.global_transform + camera_transform.origin -= camera_transform.basis.z * 0.5 + + camera_transform.basis = camera_transform.basis.rotated(camera_transform.basis.x, deg_to_rad(90)) + + global_transform = camera_transform \ No newline at end of file diff --git a/app/content/ui/menu/menu.tscn b/app/content/ui/menu/menu.tscn index 2d056a7..3de734c 100644 --- a/app/content/ui/menu/menu.tscn +++ b/app/content/ui/menu/menu.tscn @@ -18,10 +18,10 @@ size = Vector3(0.38, 0.0128076, 0.32) [sub_resource type="BoxShape3D" id="BoxShape3D_6xn1i"] size = Vector3(0.3, 0.0264844, 0.3) -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ti5t2"] +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_01s1g"] [sub_resource type="BoxMesh" id="BoxMesh_08du6"] -material = SubResource("StandardMaterial3D_ti5t2") +material = SubResource("StandardMaterial3D_01s1g") size = Vector3(0.3, 0.01, 0.3) [sub_resource type="Animation" id="Animation_61md4"] diff --git a/app/content/ui/sub_menu/sub_menu.gd b/app/content/ui/sub_menu/sub_menu.gd new file mode 100644 index 0000000..67e954f --- /dev/null +++ b/app/content/ui/sub_menu/sub_menu.gd @@ -0,0 +1 @@ +extends Node3D diff --git a/app/content/ui/sub_menu/sub_menu.tscn b/app/content/ui/sub_menu/sub_menu.tscn new file mode 100644 index 0000000..62c6226 --- /dev/null +++ b/app/content/ui/sub_menu/sub_menu.tscn @@ -0,0 +1,42 @@ +[gd_scene load_steps=6 format=3 uid="uid://cmtp5kof0ah2b"] + +[ext_resource type="Material" uid="uid://bnwimm214q67g" path="res://assets/materials/sec-500.material" id="1_mxydb"] +[ext_resource type="Script" path="res://content/ui/sub_menu/sub_menu.gd" id="1_xpjuw"] +[ext_resource type="PackedScene" uid="uid://blrhy2uccrdn4" path="res://content/ui/components/input/input.tscn" id="2_64uue"] + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ti5t2"] + +[sub_resource type="BoxMesh" id="BoxMesh_aisgf"] +material = SubResource("StandardMaterial3D_ti5t2") +size = Vector3(0.3, 0.01, 0.3) + +[node name="SubMenu" type="Node3D"] +script = ExtResource("1_xpjuw") + +[node name="Background" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.15, 0, 0.15) +material_override = ExtResource("1_mxydb") +mesh = SubResource("BoxMesh_aisgf") +skeleton = NodePath("../..") + +[node name="Content" type="Node3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.006, 0) + +[node name="Label3D" type="Label3D" parent="Content"] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0.01, 0, 0.02) +pixel_size = 0.001 +text = "Entity Name" +font_size = 24 +outline_size = 0 +horizontal_alignment = 0 + +[node name="Label3D2" type="Label3D" parent="Content"] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0.01, 0, 0.06) +pixel_size = 0.001 +text = "ID:" +font_size = 18 +outline_size = 0 +horizontal_alignment = 0 + +[node name="Input" parent="Content" instance=ExtResource("2_64uue")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.12, 0, 0.06) diff --git a/app/lib/globals/home_api.gd b/app/lib/globals/home_api.gd index 763a3d6..474af9b 100644 --- a/app/lib/globals/home_api.gd +++ b/app/lib/globals/home_api.gd @@ -2,6 +2,7 @@ extends Node ## Manages the connection to the home automation system and provides a unified interface to the different home automation systems. const Hass = preload ("res://lib/home_apis/hass/hass.gd") +const EntityGroups = preload ("res://lib/utils/entity_group.gd") const HassWebSocket = preload ("res://lib/home_apis/hass_ws/hass.gd") const VoiceAssistant = preload ("res://lib/home_apis/voice_handler.gd") @@ -18,6 +19,8 @@ const methods = [ "watch_state" ] +var groups = EntityGroups.new() + ## Emitted when the connection to the home automation system is established signal on_connect() @@ -86,16 +89,37 @@ func get_device(id: String): ## Returns the current state of an entity func get_state(entity: String): assert(has_connected(), "Not connected") + + var group = groups.get_group(entity) + + if group != null: + return await api.get_state(group[0]) + return await api.get_state(entity) ## Updates the state of the entity and returns the resulting state func set_state(entity: String, state: Variant, attributes: Dictionary={}): assert(has_connected(), "Not connected") + + var group = groups.get_group(entity) + + if group != null: + for group_entity in group: + api.set_state(group_entity, state, attributes) + + return null + return await api.set_state(entity, state, attributes) ## Watches the state and each time it changes, calls the callback with the changed state, returns a function to stop watching the state func watch_state(entity: String, callback: Callable): assert(has_connected(), "Not connected") + + var group = groups.get_group(entity) + + if group != null: + api.watch_state(group[0], callback) + return api.watch_state(entity, callback) ## Returns true if the adapter has an integration in the home automation system @@ -128,4 +152,7 @@ func get_history(entity_id, start, end=null): if api.has_method("get_history") == false: return null + if groups.is_group(entity_id): + return null + return await api.get_history(entity_id, start, end) \ No newline at end of file diff --git a/app/lib/utils/entity_group.gd b/app/lib/utils/entity_group.gd new file mode 100644 index 0000000..e4726c3 --- /dev/null +++ b/app/lib/utils/entity_group.gd @@ -0,0 +1,44 @@ +var groups = {} +var counter = 0 + +func create(entities): + var index = str(counter) + groups[index] = entities + counter += 1 + + return "group.%s" % index + +func add_entity(id: String, entity): + if is_group(id) == false: + return false + + groups[id.replace("group.", "")].append(entity) + return true + +func update_entities(id: String, entities): + if is_group(id) == false: + return false + + groups[id.replace("group.", "")] = entities + return true + +func remove_entity(id: String, entity): + if is_group(id) == false: + return false + + groups[id.replace("group.", "")].erase(entity) + return true + +func remove(id: String): + if is_group(id) == false: + return false + return groups.erase(id.replace("group.", "")) + +func is_group(id: String): + return id.begins_with("group.") + +func get_group(id: String): + if is_group(id) == false: + return null + + return groups[id.replace("group.", "")] \ No newline at end of file From 0793dd44f9303a3196d83eeb0fe3176f2849d153 Mon Sep 17 00:00:00 2001 From: Nitwel Date: Wed, 17 Apr 2024 19:49:45 +0200 Subject: [PATCH 2/6] fix dot border --- app/content/system/dot/dot.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/content/system/dot/dot.gd b/app/content/system/dot/dot.gd index 8ed2ad4..0650f44 100644 --- a/app/content/system/dot/dot.gd +++ b/app/content/system/dot/dot.gd @@ -19,7 +19,7 @@ func _ready(): # Update active R.effect(func(_arg): - label.outline_modulate=Color(242, 90, 56, 1) if active.value else Color(0, 0, 0, 1) + label.outline_modulate=Color(242 / 255.0, 90 / 255.0, 56 / 255.0, 1) if active.value else Color(0, 0, 0, 1) ) # Update disabled From d645ed7e9aafecc7aadd2b29d7f9505c1ab5cc07 Mon Sep 17 00:00:00 2001 From: Nitwel Date: Wed, 17 Apr 2024 19:57:34 +0200 Subject: [PATCH 3/6] fix dots not updating position --- app/content/entities/button/button.tscn | 2 +- app/content/system/house/house.gd | 3 ++- app/content/system/house/mini/Entity.gd | 6 +++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/content/entities/button/button.tscn b/app/content/entities/button/button.tscn index fe04a15..02be446 100644 --- a/app/content/entities/button/button.tscn +++ b/app/content/entities/button/button.tscn @@ -8,7 +8,7 @@ [sub_resource type="BoxShape3D" id="BoxShape3D_um5pa"] size = Vector3(0.0700684, 0.011734, 0.0703125) -[node name="Button" type="StaticBody3D" ] +[node name="Button" type="StaticBody3D"] script = ExtResource("1_ja7lt") [node name="Button" parent="." instance=ExtResource("1_r4tef")] diff --git a/app/content/system/house/house.gd b/app/content/system/house/house.gd index 92d1053..1d6135c 100644 --- a/app/content/system/house/house.gd +++ b/app/content/system/house/house.gd @@ -250,5 +250,6 @@ func save_all_entities(): entity_data["interface"] = entity.get_interface() Store.house.state.entities.append(entity_data) - + + Store.house.state.entities = Store.house.state.entities Store.house.save_local() diff --git a/app/content/system/house/mini/Entity.gd b/app/content/system/house/mini/Entity.gd index d7341f6..5c6915a 100644 --- a/app/content/system/house/mini/Entity.gd +++ b/app/content/system/house/mini/Entity.gd @@ -19,9 +19,11 @@ func _ready(): group_entity.queue_free() group_entity=null elif group_entity == null: - print(editing.value.map(func(entity): return entity.entity_id)) var id=HomeApi.groups.create(editing.value.map(func(entity): return entity.entity_id)) group_entity=EntityFactory.create_entity(id, active_type) + for entity_node in group_entity.get_children(): + if entity_node is Movable: + group_entity.remove_child(entity_node) add_child(group_entity) else: HomeApi.groups.update_entities(group_entity.entity_id, editing.value.map(func(entity): return entity.entity_id)) @@ -39,6 +41,8 @@ func _ready(): if Store.house.state.entities.size() == 0: return + print("Updating Dots") + for old_dot in dots.get_children(): dots.remove_child(old_dot) old_dot.free() From be958486b710602d0a696b4bcfbecc051185cf64 Mon Sep 17 00:00:00 2001 From: Nitwel Date: Wed, 17 Apr 2024 20:45:18 +0200 Subject: [PATCH 4/6] add quick actions to hand --- app/content/main.tscn | 1 + .../controller_left/controller_left.tscn | 2 +- app/content/system/hands/hands.gd | 32 ++++++++++++++ app/content/system/hands/hands.tscn | 44 ++++++++----------- app/content/system/house/mini/Entity.gd | 2 - 5 files changed, 52 insertions(+), 29 deletions(-) diff --git a/app/content/main.tscn b/app/content/main.tscn index 519f72d..ccad3d5 100644 --- a/app/content/main.tscn +++ b/app/content/main.tscn @@ -72,6 +72,7 @@ ray_right = NodePath("../XRControllerRight/Raycast") enable_passthrough = true [node name="XRSimulator" parent="." instance=ExtResource("5_3qc8g")] +min_camera_height = 0.01 xr_origin = NodePath("../XROrigin3D") [node name="Menu" parent="." instance=ExtResource("8_du83w")] diff --git a/app/content/system/controller_left/controller_left.tscn b/app/content/system/controller_left/controller_left.tscn index 9e2efd1..a18969b 100644 --- a/app/content/system/controller_left/controller_left.tscn +++ b/app/content/system/controller_left/controller_left.tscn @@ -2,7 +2,7 @@ [ext_resource type="Script" path="res://content/system/controller_left/controller_left.gd" id="1_2j3qs"] [ext_resource type="PackedScene" uid="uid://dqjcqdhe3rbtn" path="res://assets/models/trash_bin/trash_bin.gltf" id="3_m33ce"] -[ext_resource type="PackedScene" uid="uid://d3f8glx1xgm5w" path="res://content/system/raycast/raycast.tscn" id="4_n7lao"] +[ext_resource type="PackedScene" uid="uid://dscp8x0ari57n" path="res://content/system/raycast/raycast.tscn" id="4_n7lao"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m58yb"] ao_enabled = true diff --git a/app/content/system/hands/hands.gd b/app/content/system/hands/hands.gd index 00c64b9..33d3dae 100644 --- a/app/content/system/hands/hands.gd +++ b/app/content/system/hands/hands.gd @@ -5,9 +5,16 @@ const Initiator = preload ("res://lib/utils/pointer/initiator.gd") const Finger = preload ("res://lib/utils/touch/finger.gd") const Touch = preload ("res://lib/utils/touch/touch.gd") const Collide = preload ("res://lib/utils/touch/collide.gd") +const Miniature = preload ("res://content/system/house/mini/miniature.gd") +@onready var main = $"/root/Main" @onready var hand_right: OpenXRHand = $XRHandRight @onready var hand_left: OpenXRHand = $XRHandLeft +@onready var palm = $XRHandLeft/Palm +@onready var quick_actions = $XRHandLeft/Palm/QuickActions +@onready var mini_view_button = $XRHandLeft/Palm/QuickActions/MiniView +@onready var temperature_button = $XRHandLeft/Palm/QuickActions/Temperature +@onready var humidity_button = $XRHandLeft/Palm/QuickActions/Humidity @export var ray_left: RayCast3D @export var ray_right: RayCast3D var initiator: Initiator = Initiator.new() @@ -38,6 +45,24 @@ func _ready(): _ready_hand(hand_right) + mini_view_button.on_button_up.connect(func(): + House.body.mini_view.small.value=!House.body.mini_view.small.value + ) + + temperature_button.on_button_up.connect(func(): + if House.body.mini_view.heatmap_type.value == Miniature.HeatmapType.TEMPERATURE: + House.body.mini_view.heatmap_type.value=Miniature.HeatmapType.NONE + else: + House.body.mini_view.heatmap_type.value=Miniature.HeatmapType.TEMPERATURE + ) + + humidity_button.on_button_up.connect(func(): + if House.body.mini_view.heatmap_type.value == Miniature.HeatmapType.HUMIDITY: + House.body.mini_view.heatmap_type.value=Miniature.HeatmapType.NONE + else: + House.body.mini_view.heatmap_type.value=Miniature.HeatmapType.HUMIDITY + ) + func _ready_hand(hand: OpenXRHand): initiator.type = Initiator.Type.HAND_RIGHT if hand == hand_right else Initiator.Type.HAND_LEFT initiator.node = ray_left.get_parent() if hand == hand_left else ray_right.get_parent() @@ -45,7 +70,14 @@ func _ready_hand(hand: OpenXRHand): pointer = Pointer.new(initiator, ray_left if hand == hand_left else ray_right) add_child(pointer) +func _process(_delta): + if main.camera.global_transform.basis.z.dot(palm.global_transform.basis.y) > 0.85: + if quick_actions.is_inside_tree() == false: palm.add_child(quick_actions) + else: + if quick_actions.is_inside_tree(): palm.remove_child(quick_actions) + func _physics_process(_delta): + _process_hand(hand_left) _process_hand(hand_right) func _process_hand(hand: OpenXRHand): diff --git a/app/content/system/hands/hands.tscn b/app/content/system/hands/hands.tscn index 937bda1..6cb3398 100644 --- a/app/content/system/hands/hands.tscn +++ b/app/content/system/hands/hands.tscn @@ -3,6 +3,7 @@ [ext_resource type="Script" path="res://content/system/hands/hands.gd" id="1_c4f76"] [ext_resource type="PackedScene" uid="uid://c0kow4g10wolq" path="res://assets/models/hands_steam/right_hand.glb" id="1_uekbj"] [ext_resource type="PackedScene" uid="uid://dt4ksvogfctkr" path="res://assets/models/hands_steam/left_hand.glb" id="2_n73lt"] +[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="3_te2p8"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_3bjtw"] transparency = 1 @@ -12,9 +13,6 @@ albedo_color = Color(1, 1, 1, 0.705882) radius = 0.001 height = 0.02 -[sub_resource type="BoxShape3D" id="BoxShape3D_1pxrt"] -size = Vector3(0.14, 0.0224609, 0.169383) - [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_n27ki"] transparency = 1 albedo_color = Color(1, 1, 1, 0.705882) @@ -82,18 +80,25 @@ monitorable = false transform = Transform3D(1, -7.45058e-09, -2.22045e-16, 7.45058e-09, 1, 0, 0, 0, 1, 0, 0, 0) shape = SubResource("CapsuleShape3D_dopke") -[node name="AnimatableBody3D" type="AnimatableBody3D" parent="XRHandLeft"] -transform = Transform3D(1, 8.67362e-19, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) -collision_layer = 8 -collision_mask = 8 +[node name="Palm" type="Node3D" parent="XRHandLeft"] +transform = Transform3D(-0.707107, -8.74228e-08, -0.707107, 6.18173e-08, -1, 6.18173e-08, -0.707107, -8.29045e-24, 0.707107, 0.01, -0.04, -5.58794e-09) -[node name="CollisionShape3D" type="CollisionShape3D" parent="XRHandLeft/AnimatableBody3D"] -transform = Transform3D(1, 1.05818e-16, 4.75779e-13, -2.32831e-10, 1, -1.77636e-14, -4.97946e-12, 1.77636e-15, 1, -7.7486e-07, 1.33878e-09, -0.030436) -shape = SubResource("BoxShape3D_1pxrt") -disabled = true +[node name="QuickActions" type="Node3D" parent="XRHandLeft/Palm"] +transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0) -[node name="RemoteTransform3D" type="RemoteTransform3D" parent="XRHandLeft"] -remote_path = NodePath("../AnimatableBody3D") +[node name="MiniView" parent="XRHandLeft/Palm/QuickActions" instance=ExtResource("3_te2p8")] +transform = Transform3D(1, -3.55271e-15, -4.33681e-19, 3.55271e-15, 1, 3.5525e-15, -4.33681e-19, -3.55291e-15, 1, -0.0600001, 0, 0) +label = "nest_multi_room" +icon = true + +[node name="Temperature" parent="XRHandLeft/Palm/QuickActions" instance=ExtResource("3_te2p8")] +label = "device_thermostat" +icon = true + +[node name="Humidity" parent="XRHandLeft/Palm/QuickActions" instance=ExtResource("3_te2p8")] +transform = Transform3D(1, 1.73472e-18, 0, 0, 1, 0, 0, 0, 1, 0.0600001, -5.68873e-13, 0) +label = "humidity_mid" +icon = true [node name="XRHandRight" type="OpenXRHand" parent="."] transform = Transform3D(0.999998, -0.000567105, 2.47889e-11, 0, -4.37113e-08, -0.999999, 0.000567104, 0.999999, -4.37113e-08, 0.264391, 0, 0) @@ -156,18 +161,5 @@ monitorable = false transform = Transform3D(1, -7.45058e-09, -2.22045e-16, 7.45058e-09, 1, 0, 0, 0, 1, 0, 0, 0) shape = SubResource("CapsuleShape3D_dopke") -[node name="AnimatableBody3D" type="AnimatableBody3D" parent="XRHandRight"] -transform = Transform3D(1, 0, 0, 0, 1, 3.55271e-15, 0, -3.55271e-15, 1, 0, 0, 0) -collision_layer = 8 -collision_mask = 8 - -[node name="CollisionShape3D" type="CollisionShape3D" parent="XRHandRight/AnimatableBody3D"] -transform = Transform3D(1, 0, 4.75779e-13, -2.32831e-10, 1, -1.77636e-14, -4.97946e-12, 1.77636e-15, 1, -7.7486e-07, 1.33878e-09, -0.030436) -shape = SubResource("BoxShape3D_1pxrt") -disabled = true - -[node name="RemoteTransform3D" type="RemoteTransform3D" parent="XRHandRight"] -remote_path = NodePath("../AnimatableBody3D") - [editable path="XRHandLeft/left_hand"] [editable path="XRHandRight/right_hand"] diff --git a/app/content/system/house/mini/Entity.gd b/app/content/system/house/mini/Entity.gd index 5c6915a..1629924 100644 --- a/app/content/system/house/mini/Entity.gd +++ b/app/content/system/house/mini/Entity.gd @@ -41,8 +41,6 @@ func _ready(): if Store.house.state.entities.size() == 0: return - print("Updating Dots") - for old_dot in dots.get_children(): dots.remove_child(old_dot) old_dot.free() From d858dc54e5090dd2e8bea8836bb4cce3ccd239be Mon Sep 17 00:00:00 2001 From: Nitwel Date: Wed, 17 Apr 2024 21:27:09 +0200 Subject: [PATCH 5/6] fix long press and add quick actions --- app/content/entities/button/button.gd | 3 +++ app/content/entities/light/light.gd | 9 +++++++++ app/content/entities/switch/switch.gd | 11 +++++++++-- app/content/system/dot/dot.gd | 22 ++++++++++++++++++++-- app/content/system/dot/dot.tscn | 14 +++++++++++++- 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/app/content/entities/button/button.gd b/app/content/entities/button/button.gd index 09b6f93..0533788 100644 --- a/app/content/entities/button/button.gd +++ b/app/content/entities/button/button.gd @@ -34,3 +34,6 @@ func set_state(state): else: button.icon = false button.label = name + +func quick_action(): + HomeApi.set_state(entity_id, "pressed") \ No newline at end of file diff --git a/app/content/entities/light/light.gd b/app/content/entities/light/light.gd index e61366f..b867392 100644 --- a/app/content/entities/light/light.gd +++ b/app/content/entities/light/light.gd @@ -132,3 +132,12 @@ func _on_click(event): HomeApi.set_state(entity_id, "on" if !state else "off", attributes) set_state(!state, attributes) + +func quick_action(): + var attributes = {} + + if !state&&brightness != null: + attributes["brightness"] = int(brightness) + + HomeApi.set_state(entity_id, "on" if !state else "off", attributes) + set_state(!state, attributes) \ No newline at end of file diff --git a/app/content/entities/switch/switch.gd b/app/content/entities/switch/switch.gd index 4cb1b19..1a0c5d7 100644 --- a/app/content/entities/switch/switch.gd +++ b/app/content/entities/switch/switch.gd @@ -27,7 +27,7 @@ func _ready(): icon.value="toggle_" + new_state["state"] ) -func _on_click(event): +func _on_click(_event): HomeApi.set_state(entity_id, "off" if sprite.get_frame() == 0 else "on") if sprite.get_frame() == 0: sprite.set_frame(1) @@ -35,4 +35,11 @@ func _on_click(event): sprite.set_frame(0) func _on_request_completed(): - pass \ No newline at end of file + pass + +func quick_action(): + HomeApi.set_state(entity_id, "off" if sprite.get_frame() == 0 else "on") + if sprite.get_frame() == 0: + sprite.set_frame(1) + else: + sprite.set_frame(0) \ No newline at end of file diff --git a/app/content/system/dot/dot.gd b/app/content/system/dot/dot.gd index 0650f44..89e175b 100644 --- a/app/content/system/dot/dot.gd +++ b/app/content/system/dot/dot.gd @@ -2,12 +2,16 @@ extends StaticBody3D const Entity = preload ("res://content/entities/entity.gd") +const TOUCH_LONG = 400.0 + @export var entity: Entity @onready var collision = $CollisionShape3D @onready var label = $Label3D var active = R.state(false) var disabled = R.state(true) +var touched_enter = 0.0 +var moved_ran = false var miniature = House.body.mini_view @@ -34,5 +38,19 @@ func _on_click(_event: EventPointer): else: miniature.entity_select.toggle(entity) -func _on_move_start(_event: EventPointer): - miniature.entity_select.toggle(entity) \ No newline at end of file +func _on_press_move(_event: EventPointer): + if moved_ran: return + miniature.entity_select.toggle(entity) + moved_ran = true + +func _on_press_up(_event: EventPointer): + moved_ran = false + +func _on_touch_enter(_event: EventTouch): + touched_enter = Time.get_ticks_msec() + +func _on_touch_leave(_event: EventTouch): + if Time.get_ticks_msec() - touched_enter < TOUCH_LONG&&entity.has_method("quick_action"): + entity.quick_action() + else: + miniature.entity_select.toggle(entity) \ No newline at end of file diff --git a/app/content/system/dot/dot.tscn b/app/content/system/dot/dot.tscn index 4e1901b..5d307ed 100644 --- a/app/content/system/dot/dot.tscn +++ b/app/content/system/dot/dot.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=4 format=3 uid="uid://b5buw1sas18n4"] +[gd_scene load_steps=5 format=3 uid="uid://b5buw1sas18n4"] [ext_resource type="Script" path="res://content/system/dot/dot.gd" id="1_vdpux"] [ext_resource type="FontVariation" uid="uid://sshfnckriqxn" path="res://assets/icons/icons.tres" id="4_504vw"] @@ -7,6 +7,10 @@ custom_solver_bias = 0.2 radius = 0.1 +[sub_resource type="SphereShape3D" id="SphereShape3D_y1ne8"] +custom_solver_bias = 0.2 +radius = 0.2 + [node name="Dot" type="StaticBody3D"] script = ExtResource("1_vdpux") @@ -20,3 +24,11 @@ text = "lightbulb" font = ExtResource("4_504vw") font_size = 100 outline_size = 18 + +[node name="Area3D" type="Area3D" parent="."] +collision_layer = 4 +collision_mask = 0 +monitoring = false + +[node name="CollisionShape3D2" type="CollisionShape3D" parent="Area3D"] +shape = SubResource("SphereShape3D_y1ne8") From 1f2ca1e1a799f6657bd0b17b570004013c4383f3 Mon Sep 17 00:00:00 2001 From: Nitwel Date: Wed, 17 Apr 2024 21:34:21 +0200 Subject: [PATCH 6/6] improve dot touch --- app/content/system/dot/dot.gd | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/content/system/dot/dot.gd b/app/content/system/dot/dot.gd index 89e175b..faded69 100644 --- a/app/content/system/dot/dot.gd +++ b/app/content/system/dot/dot.gd @@ -12,6 +12,7 @@ var active = R.state(false) var disabled = R.state(true) var touched_enter = 0.0 var moved_ran = false +var touch_ran = false var miniature = House.body.mini_view @@ -48,9 +49,19 @@ func _on_press_up(_event: EventPointer): func _on_touch_enter(_event: EventTouch): touched_enter = Time.get_ticks_msec() + touch_ran = false + +func _on_touch_move(_event: EventTouch): + if touch_ran||Time.get_ticks_msec() - touched_enter < TOUCH_LONG: return + + miniature.entity_select.toggle(entity) + + touch_ran = true func _on_touch_leave(_event: EventTouch): - if Time.get_ticks_msec() - touched_enter < TOUCH_LONG&&entity.has_method("quick_action"): + if touch_ran: return + + if entity.has_method("quick_action"): entity.quick_action() else: miniature.entity_select.toggle(entity) \ No newline at end of file