diff --git a/assets/design.afdesign b/assets/design.afdesign new file mode 100644 index 0000000..35321b1 --- /dev/null +++ b/assets/design.afdesign @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a3a3204f122024fe25657532ccbe1c0d07eba475f37ebb686046ba71d358ad58 +size 2087560 diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 0000000..140c2c9 --- /dev/null +++ b/assets/logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b5d79d4a0c78bcce53fb01fa0353ec971eca5f6f8f3fb1fa7322f18f87a4781b +size 1122652 diff --git a/assets/logo.png.import b/assets/logo.png.import new file mode 100644 index 0000000..1605cdd --- /dev/null +++ b/assets/logo.png.import @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1daf27643292c3a222f2a9e60dfe38db5e62963cbfa2dd313588aa98f4e053b4 +size 753 diff --git a/assets/materials/swich_on.png b/assets/materials/swich_on.png new file mode 100644 index 0000000..0319380 --- /dev/null +++ b/assets/materials/swich_on.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:06c7745de9d5236d8096979e16708530a3c61112b604a7603033ea8bc9097791 +size 258636 diff --git a/assets/materials/swich_on.png.import b/assets/materials/swich_on.png.import new file mode 100644 index 0000000..f74b6ff --- /dev/null +++ b/assets/materials/swich_on.png.import @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b936cb0718d6b36ba9070d10fe2a16b2dbff0a4f9649e80205e3218fdb4b9df9 +size 1007 diff --git a/assets/materials/switch_off.png b/assets/materials/switch_off.png new file mode 100644 index 0000000..b05a9be --- /dev/null +++ b/assets/materials/switch_off.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3fa30c33f89997925bc7164245d51209879a912597a72b227b861f9a9841acec +size 249715 diff --git a/assets/materials/switch_off.png.import b/assets/materials/switch_off.png.import new file mode 100644 index 0000000..4e74575 --- /dev/null +++ b/assets/materials/switch_off.png.import @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:71e68850377c2368a7433084c550cc7c5fa5110184cf59fc6d7a8f77f5f4af89 +size 1017 diff --git a/main.tscn b/main.tscn index f8bc998..79ccc7c 100644 --- a/main.tscn +++ b/main.tscn @@ -1,18 +1,10 @@ -[gd_scene load_steps=13 format=3 uid="uid://eecv28y6jxk4"] +[gd_scene load_steps=10 format=3 uid="uid://eecv28y6jxk4"] -[ext_resource type="Script" path="res://src/devices/light.gd" id="1_5mqma"] [ext_resource type="PackedScene" uid="uid://clc5dre31iskm" path="res://addons/godot-xr-tools/xr/start_xr.tscn" id="1_i4c04"] [ext_resource type="Script" path="res://src/raycast.gd" id="1_tsqxc"] [ext_resource type="Script" path="res://src/model.gd" id="2_7f1x4"] [ext_resource type="PackedScene" uid="uid://c3kdssrmv84kv" path="res://scenes/menu.tscn" id="3_1tbp3"] -[sub_resource type="SphereShape3D" id="SphereShape3D_2igmd"] -radius = 0.1 - -[sub_resource type="SphereMesh" id="SphereMesh_eme7e"] -radius = 0.1 -height = 0.2 - [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m58yb"] ao_enabled = true @@ -41,16 +33,6 @@ ambient_light_sky_contribution = 0.72 [node name="Main" type="Node3D"] -[node name="Light" type="StaticBody3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.45064, 0, 0.20152) -script = ExtResource("1_5mqma") - -[node name="CollisionShape3D" type="CollisionShape3D" parent="Light"] -shape = SubResource("SphereShape3D_2igmd") - -[node name="MeshInstance3D" type="MeshInstance3D" parent="Light"] -mesh = SubResource("SphereMesh_eme7e") - [node name="XROrigin3D" type="XROrigin3D" parent="."] [node name="XRCamera3D" type="XRCamera3D" parent="XROrigin3D"] @@ -64,9 +46,8 @@ pose = &"aim" [node name="MeshInstance3D" type="MeshInstance3D" parent="XROrigin3D/XRControllerLeft"] mesh = SubResource("BoxMesh_ir3co") -[node name="Model" type="Node3D" parent="XROrigin3D/XRControllerLeft" node_paths=PackedStringArray("light")] +[node name="Model" type="Node3D" parent="XROrigin3D/XRControllerLeft"] script = ExtResource("2_7f1x4") -light = NodePath("../../../Light") [node name="Menu" parent="XROrigin3D/XRControllerLeft" instance=ExtResource("3_1tbp3")] transform = Transform3D(-4.37114e-08, 0, -1, -0.707107, 0.707107, 3.09086e-08, 0.707107, 0.707107, -3.09086e-08, 0.194945, 0, -0.0534939) diff --git a/scenes/entities/light.tscn b/scenes/entities/light.tscn new file mode 100644 index 0000000..37de134 --- /dev/null +++ b/scenes/entities/light.tscn @@ -0,0 +1,33 @@ +[gd_scene load_steps=6 format=3 uid="uid://cw86rc42dv2d8"] + +[ext_resource type="Script" path="res://src/entities/light.gd" id="1_ykxy3"] +[ext_resource type="Texture2D" uid="uid://b72vsbcvqqxg7" path="res://assets/materials/swich_on.png" id="2_6gn2e"] +[ext_resource type="Texture2D" uid="uid://cvc0o6dsktnvl" path="res://assets/materials/switch_off.png" id="3_qlm62"] + +[sub_resource type="SphereShape3D" id="SphereShape3D_ukj14"] +radius = 0.1 + +[sub_resource type="SpriteFrames" id="SpriteFrames_ldpuo"] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": ExtResource("2_6gn2e") +}, { +"duration": 1.0, +"texture": ExtResource("3_qlm62") +}], +"loop": true, +"name": &"default", +"speed": 5.0 +}] + +[node name="Light" type="StaticBody3D"] +script = ExtResource("1_ykxy3") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +shape = SubResource("SphereShape3D_ukj14") + +[node name="Icon" type="AnimatedSprite3D" parent="."] +pixel_size = 0.0005 +billboard = 1 +sprite_frames = SubResource("SpriteFrames_ldpuo") diff --git a/scenes/entities/switch.tscn b/scenes/entities/switch.tscn new file mode 100644 index 0000000..d99fce8 --- /dev/null +++ b/scenes/entities/switch.tscn @@ -0,0 +1,33 @@ +[gd_scene load_steps=6 format=3 uid="uid://cscl5k7lhopj5"] + +[ext_resource type="Script" path="res://src/entities/switch.gd" id="1_8ffhi"] +[ext_resource type="Texture2D" uid="uid://b72vsbcvqqxg7" path="res://assets/materials/swich_on.png" id="1_w68gw"] +[ext_resource type="Texture2D" uid="uid://cvc0o6dsktnvl" path="res://assets/materials/switch_off.png" id="2_86ba1"] + +[sub_resource type="SphereShape3D" id="SphereShape3D_ukj14"] +radius = 0.1 + +[sub_resource type="SpriteFrames" id="SpriteFrames_ldpuo"] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": ExtResource("1_w68gw") +}, { +"duration": 1.0, +"texture": ExtResource("2_86ba1") +}], +"loop": true, +"name": &"default", +"speed": 5.0 +}] + +[node name="Switch" type="StaticBody3D"] +script = ExtResource("1_8ffhi") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +shape = SubResource("SphereShape3D_ukj14") + +[node name="Icon" type="AnimatedSprite3D" parent="."] +pixel_size = 0.0005 +billboard = 1 +sprite_frames = SubResource("SpriteFrames_ldpuo") diff --git a/src/devices/light.gd b/src/devices/light.gd deleted file mode 100644 index cc8d680..0000000 --- a/src/devices/light.gd +++ /dev/null @@ -1,27 +0,0 @@ -extends StaticBody3D - -@onready var http_request = HTTPRequest.new() -@export var id = "switch.plug_printer_2" -@export var token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIzZjQ0ZGM2N2Y3YzY0MDc1OGZlMWI2ZjJlNmIxZjRkNSIsImlhdCI6MTY5ODAxMDcyOCwiZXhwIjoyMDEzMzcwNzI4fQ.K6ydLUC-4Q7BNIRCU1nWlI2s6sg9UCiOu-Lpedw2zJc" - -# Called when the node enters the scene tree for the first time. -func _ready(): - add_child(http_request) - http_request.request_completed.connect(self._on_request_completed) - - -# Called every frame. 'delta' is the elapsed time since the previous frame. -func _process(delta): - pass - -func _on_toggle(): - print("Toggling " + id) - var headers = PackedStringArray(["Authorization: Bearer " + token, "Content-Type: application/json"]) - - var error = http_request.request("http://192.168.33.33:8123/api/services/switch/toggle", headers, HTTPClient.METHOD_POST, "{\"entity_id\": \"" + id + "\"}") - - if error != OK: - push_error("An error occurred in the HTTP request.") - -func _on_request_completed(): - pass diff --git a/src/entities/light.gd b/src/entities/light.gd new file mode 100644 index 0000000..5f77c50 --- /dev/null +++ b/src/entities/light.gd @@ -0,0 +1,23 @@ +extends StaticBody3D + +@export var entity_id = "switch.plug_printer_2" +@onready var sprite: AnimatedSprite3D = $Icon + +# Called when the node enters the scene tree for the first time. +func _ready(): + var stateInfo = await HomeAdapters.adapter.get_state(entity_id) + if stateInfo["state"] == "on": + sprite.set_frame(0) + else: + sprite.set_frame(1) + + +func _on_toggle(): + HomeAdapters.adapter.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) + +func _on_request_completed(): + pass diff --git a/src/entities/switch.gd b/src/entities/switch.gd new file mode 100644 index 0000000..5f77c50 --- /dev/null +++ b/src/entities/switch.gd @@ -0,0 +1,23 @@ +extends StaticBody3D + +@export var entity_id = "switch.plug_printer_2" +@onready var sprite: AnimatedSprite3D = $Icon + +# Called when the node enters the scene tree for the first time. +func _ready(): + var stateInfo = await HomeAdapters.adapter.get_state(entity_id) + if stateInfo["state"] == "on": + sprite.set_frame(0) + else: + sprite.set_frame(1) + + +func _on_toggle(): + HomeAdapters.adapter.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) + +func _on_request_completed(): + pass diff --git a/src/home_adapters/adapter.gd b/src/home_adapters/adapter.gd index c18ae44..21c862d 100644 --- a/src/home_adapters/adapter.gd +++ b/src/home_adapters/adapter.gd @@ -11,7 +11,9 @@ const adapters = { } const methods = [ - "load_devices" + "load_devices", + "get_state", + "set_state" ] var adapter: Node @@ -24,3 +26,9 @@ func _init(type: ADAPTER_TYPES): func load_devices(): return await adapter.load_devices() + +func get_state(entity: String): + return await adapter.get_state(entity) + +func set_state(entity: String, state: String, attributes: Dictionary = {}): + return await adapter.set_state(entity, state, attributes) \ No newline at end of file diff --git a/src/home_adapters/hass/hass.gd b/src/home_adapters/hass/hass.gd index 9c0bc35..93d2aa1 100644 --- a/src/home_adapters/hass/hass.gd +++ b/src/home_adapters/hass/hass.gd @@ -21,3 +21,43 @@ func load_devices(): print(json) return json + +func get_state(entity: String): + var type = entity.split('.')[0] + + Request.request("%s/api/states/%s" % [url, entity], headers, HTTPClient.METHOD_GET) + var response = await Request.request_completed + + var data_string = response[3].get_string_from_utf8().replace("'", "\"") + var json = JSON.parse_string(data_string) + + print(json) + return json + + + +func set_state(entity: String, state: String, attributes: Dictionary = {}): + var type = entity.split('.')[0] + var response + + if type == 'switch': + if state == 'on': + Request.request("%s/api/services/switch/turn_on" % [url], headers, HTTPClient.METHOD_POST, "{\"entity_id\": \"%s\"}" % [entity]) + response = await Request.request_completed + elif state == 'off': + Request.request("%s/api/services/switch/turn_off" % [url], headers, HTTPClient.METHOD_POST, "{\"entity_id\": \"%s\"}" % [entity]) + response = await Request.request_completed + elif type == 'light': + if state == 'on': + Request.request("%s/api/services/light/turn_on" % [url], headers, HTTPClient.METHOD_POST, "{\"entity_id\": \"%s\"}" % [entity]) + response = await Request.request_completed + elif state == 'off': + Request.request("%s/api/services/light/turn_off" % [url], headers, HTTPClient.METHOD_POST, "{\"entity_id\": \"%s\"}" % [entity]) + response = await Request.request_completed + + var data_string = response[3].get_string_from_utf8().replace("'", "\"") + var json = JSON.parse_string(data_string) + + print(json) + return json + diff --git a/src/menu.gd b/src/menu.gd index da4d042..b50aff6 100644 --- a/src/menu.gd +++ b/src/menu.gd @@ -2,6 +2,8 @@ extends Node3D const Device = preload("res://scenes/device.tscn") const Entity = preload("res://scenes/entity.tscn") +const Switch = preload("res://scenes/entities/switch.tscn") +const Light = preload("res://scenes/entities/light.tscn") @onready var devices_node = $Devices var devices @@ -22,6 +24,7 @@ func render_devices(): var device_instance = Device.instantiate() device_instance.set_position(Vector3(y * 0.08, 0, -x * 0.08)) device_instance.click.connect(_on_device_click) + device_instance.id = device.keys()[0] devices_node.add_child(device_instance) @@ -39,7 +42,7 @@ func render_entities(): var info for device in devices: - if device.values()[0].name == selected_device: + if device.keys()[0] == selected_device: info = device.values()[0] break @@ -62,8 +65,8 @@ func render_entities(): x = 0 y += 1 -func _on_device_click(device_name): - selected_device = device_name +func _on_device_click(device_id): + selected_device = device_id print(selected_device) clear_menu() render_entities() @@ -73,6 +76,23 @@ func _on_entity_click(entity_name): selected_device = null clear_menu() render_devices() + + var type = entity_name.split(".")[0] + print(type) + + if type == "switch": + var switch = Switch.instantiate() + switch.entity_id = entity_name + + switch.set_position(global_position) + get_node("/root").add_child(switch) + + if type == "light": + var light = Light.instantiate() + light.entity_id = entity_name + + light.set_position(global_position) + get_node("/root").add_child(light) func clear_menu(): for child in devices_node.get_children(): diff --git a/src/ui/device.gd b/src/ui/device.gd index d112556..e11ab14 100644 --- a/src/ui/device.gd +++ b/src/ui/device.gd @@ -1,11 +1,12 @@ extends StaticBody3D @onready var label: Label3D = $Label +@export var id: String = "0" -signal click(name: String) +signal click(id: String) func _on_toggle(): - click.emit(label.text) + click.emit(id) func set_device_name(text): assert(label != null, "Device has to be added to the scene tree") diff --git a/src/ui/entity.gd b/src/ui/entity.gd index 0d5a281..e324331 100644 --- a/src/ui/entity.gd +++ b/src/ui/entity.gd @@ -1,12 +1,14 @@ extends StaticBody3D @onready var label: Label3D = $Label +@export var text = "Default" signal click(name: String) func _on_toggle(): - click.emit(label.text) + click.emit(text) func set_entity_name(text): assert(label != null, "Entity has to be added to the scene tree") - label.text = text + label.text = text.replace(".", "\n") + self.text = text