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