add onboarding flow

This commit is contained in:
Nitwel 2024-03-17 17:05:45 +01:00
parent bd5b630c04
commit ffdb1b607f
13 changed files with 193 additions and 34 deletions

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=16 format=3 uid="uid://eecv28y6jxk4"]
[gd_scene load_steps=17 format=3 uid="uid://eecv28y6jxk4"]
[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://content/main.gd" id="1_uvrd4"]
@ -11,6 +11,7 @@
[ext_resource type="PackedScene" uid="uid://c3kdssrmv84kv" path="res://content/ui/menu/menu.tscn" id="8_du83w"]
[ext_resource type="PackedScene" uid="uid://lrehk38exd5n" path="res://content/system/keyboard/keyboard.tscn" id="9_e5n3p"]
[ext_resource type="PackedScene" uid="uid://cbemihbxkd4ll" path="res://content/system/house/house.tscn" id="9_np6mw"]
[ext_resource type="PackedScene" uid="uid://bhyddd1f0ry1x" path="res://content/ui/onboarding/onboarding.tscn" id="12_uq2nj"]
[sub_resource type="Sky" id="Sky_vhymk"]
sky_material = ExtResource("5_wgwf8")
@ -83,4 +84,7 @@ transform = Transform3D(0.499999, -0.000139169, -6.50204e-05, 5.24307e-05, 0.353
[node name="House" parent="." instance=ExtResource("9_np6mw")]
[node name="Onboarding" parent="." instance=ExtResource("12_uq2nj")]
transform = Transform3D(0.999999, -1.39632e-11, 0, 9.48097e-12, 0.999999, 0, 0, 0, 0.999999, -0.529594, 0.820154, -0.600147)
[editable path="XROrigin3D/XRControllerLeft"]

View File

@ -1,5 +1,6 @@
extends Node3D
const VoiceAssistant = preload ("res://lib/home_apis/voice_handler.gd")
const sample_hold = preload ("res://lib/utils/sample_hold.gd")
const Chat = preload ("./chat.gd")
@ -19,18 +20,27 @@ var effect: AudioEffectCapture
@onready var camera = $"/root/Main/XROrigin3D/XRCamera3D"
var running := false
var voice_assistant: VoiceAssistant
func _ready():
var index = AudioServer.get_bus_index("Record")
effect = AudioServer.get_bus_effect(index, 0)
if !HomeApi.has_connected():
await HomeApi.on_connect
voice_assistant = HomeApi.get_voice_assistant()
if voice_assistant == null:
return
finish()
audio_timer.timeout.connect(func():
HomeApi.api.assist_handler.send_data(PackedByteArray())
voice_assistant.send_data(PackedByteArray())
)
HomeApi.api.assist_handler.on_wake_word.connect(func(text):
voice_assistant.on_wake_word.connect(func(_text):
loader.visible=true
chat_user.visible=false
chat_assistant.visible=false
@ -40,24 +50,24 @@ func _ready():
running=true
)
HomeApi.api.assist_handler.on_stt_message.connect(func(text):
voice_assistant.on_stt_message.connect(func(text):
loader.visible=false
chat_user.visible=true
chat_user.text=text
)
HomeApi.api.assist_handler.on_tts_message.connect(func(text):
voice_assistant.on_tts_message.connect(func(text):
chat_assistant.visible=true
chat_assistant.text=text
)
HomeApi.api.assist_handler.on_tts_sound.connect(func(audio):
voice_assistant.on_tts_sound.connect(func(audio):
audio_player_3d.stream=audio
audio_player_3d.play()
visual_timer.start()
running=false
)
HomeApi.api.assist_handler.on_error.connect(func():
voice_assistant.on_error.connect(func():
running=false
finish()
)
@ -101,9 +111,9 @@ func _process(_delta):
if max_amplitude > input_threshold:
if audio_timer.is_stopped():
HomeApi.api.assist_handler.start_wakeword()
voice_assistant.start_wakeword()
audio_timer.start()
if audio_timer.is_stopped() == false:
HomeApi.api.assist_handler.send_data(data)
voice_assistant.send_data(data)

View File

@ -3,7 +3,7 @@ extends XRCamera3D
var last_room = null
func _physics_process(_delta):
if HomeApi.api.has_integration():
if HomeApi.has_integration():
update_room()
func update_room():
@ -11,8 +11,8 @@ func update_room():
if room != last_room:
if room:
HomeApi.api.update_room(room.name)
HomeApi.update_room(room.name)
last_room = room
else:
HomeApi.api.update_room("outside")
HomeApi.update_room("outside")
last_room = null

View File

@ -5,8 +5,8 @@ extends StaticBody3D
var max_message = 30
var messages: Array = ["aaa", "bbb"]
func log(text: String) -> void:
messages.push_front(text)
func log(text: Variant) -> void:
messages.push_front(str(text))
if messages.size() > max_message:
messages.pop_back()

View File

@ -0,0 +1,43 @@
extends Node3D
@onready var getting_started_button = $GettingStartedButton
@onready var close_button = $CloseButton
@onready var camera = $"/root/Main/XROrigin3D/XRCamera3D"
var next_new_position = global_position
func _ready():
if Store.settings.is_loaded() == false:
await Store.settings.on_loaded
if (Store.settings.url != ""&&Store.settings.url != null)||Store.settings.onboarding_complete:
close()
return
getting_started_button.on_button_down.connect(func():
OS.shell_open("https://docs.immersive-home.org/")
)
close_button.on_button_down.connect(func():
close()
)
EventSystem.on_slow_tick.connect(_slow_tick)
func close():
Store.settings.onboarding_complete = true
Store.settings.save_local()
queue_free()
func _slow_tick(delta):
var new_position = camera.global_position + camera.global_transform.basis.z * - 0.5
if next_new_position.distance_to(new_position) > 0.2:
next_new_position = new_position
var new_direction = Basis.looking_at((camera.global_position - new_position) * - 1)
var tween = create_tween()
tween.set_parallel(true)
tween.set_trans(Tween.TransitionType.TRANS_QUAD)
tween.tween_property(self, "global_position", new_position, 0.6)
tween.tween_property(self, "global_transform:basis", new_direction, 0.6)

View File

@ -0,0 +1,68 @@
[gd_scene load_steps=6 format=3 uid="uid://bhyddd1f0ry1x"]
[ext_resource type="Script" path="res://content/ui/onboarding/onboarding.gd" id="1_k4yvw"]
[ext_resource type="Material" uid="uid://bujy3egn1oqac" path="res://assets/materials/pri-500.material" id="2_aleti"]
[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="3_hlpow"]
[sub_resource type="BoxShape3D" id="BoxShape3D_nfwtf"]
size = Vector3(0.5, 0.3, 0.01)
[sub_resource type="BoxMesh" id="BoxMesh_yknqs"]
size = Vector3(0.5, 0.3, 0.01)
[node name="Onboarding" type="StaticBody3D"]
script = ExtResource("1_k4yvw")
[node name="Label3D2" type="Label3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.23, -0.1, 0.006)
pixel_size = 0.001
text = "Getting Started"
font_size = 18
outline_size = 0
horizontal_alignment = 0
vertical_alignment = 0
autowrap_mode = 3
width = 470.0
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("BoxShape3D_nfwtf")
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
material_override = ExtResource("2_aleti")
mesh = SubResource("BoxMesh_yknqs")
[node name="GettingStartedLabel" type="Label3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.23, 0.14, 0.006)
pixel_size = 0.001
text = "Hey!
This app is still early in development and still has a lot of rough edges. Things might break or are sometimes difficult to use, this will improve the more the app ages.
If this is the first time you try the app, please first read through the \"Getting Started\" Guide below."
font_size = 18
outline_size = 0
horizontal_alignment = 0
vertical_alignment = 0
autowrap_mode = 3
width = 470.0
[node name="GettingStartedButton" parent="." instance=ExtResource("3_hlpow")]
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, -0.05, -0.11, 0)
label = "open_in_new"
icon = true
[node name="CloseButton" parent="." instance=ExtResource("3_hlpow")]
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0.21, -0.11, 0)
label = "done"
icon = true
[node name="CloseLabel" type="Label3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06, -0.1, 0.006)
pixel_size = 0.001
text = "Understood"
font_size = 18
outline_size = 0
horizontal_alignment = 0
vertical_alignment = 0
autowrap_mode = 3
width = 470.0

View File

@ -3,6 +3,7 @@ extends Node
const Hass = preload ("res://lib/home_apis/hass/hass.gd")
const HassWebSocket = preload ("res://lib/home_apis/hass_ws/hass.gd")
const VoiceAssistant = preload ("res://lib/home_apis/voice_handler.gd")
const apis = {
"hass": Hass,
@ -96,7 +97,26 @@ func watch_state(entity: String, callback: Callable):
assert(has_connected(), "Not connected")
return api.watch_state(entity, callback)
func _notification(what):
if what == NOTIFICATION_WM_CLOSE_REQUEST||what == NOTIFICATION_WM_GO_BACK_REQUEST:
# Store.house.save_local()
pass
## Returns true if the adapter has an integration in the home automation system
## allowing to send the room position of the headset.
func has_integration() -> bool:
if has_connected() == false||api.has_method("has_integration") == false:
return false
return api.has_integration()
## Updates the room position of the headset in the home automation system
func update_room(room: String) -> void:
if has_connected() == false||api.has_method("update_room") == false:
return
api.update_room(room)
## Returns the VoiceHandler if the adapter has a voice assistant
func get_voice_assistant() -> VoiceAssistant:
assert(has_connected(), "Not connected")
if api.has_method("get_voice_assistant") == false:
return null
return api.get_voice_assistant()

View File

@ -5,6 +5,6 @@ const SettingsStore = preload ("res://lib/stores/settings.gd")
const HouseStore = preload ("res://lib/stores/house.gd")
const DevicesStore = preload ("res://lib/stores/devices.gd")
var settings = SettingsStore.new()
var house = HouseStore.new()
var devices = DevicesStore.new()
var settings := SettingsStore.new()
var house := HouseStore.new()
var devices := DevicesStore.new()

View File

@ -1,10 +1,7 @@
const HASS_API = preload ("../hass.gd")
extends VoiceHandler
signal on_wake_word(wake_word: String)
signal on_stt_message(message: String)
signal on_tts_message(message: String)
signal on_tts_sound(sound: AudioStreamMP3)
signal on_error()
const HASS_API = preload ("../hass.gd")
const VoiceHandler = preload ("res://lib/home_apis/voice_handler.gd")
var api: HASS_API
var pipe_running := false
@ -36,9 +33,6 @@ var tts_sound = null:
func _init(hass: HASS_API):
self.api = hass
func on_connect():
pass
func start_wakeword():
if pipe_running:
return

View File

@ -121,7 +121,6 @@ func start_subscriptions():
func handle_connect():
integration_handler.on_connect()
assist_handler.on_connect()
connected = true
on_connect.emit()
@ -283,3 +282,6 @@ func update_room(room: String):
if response.status == Promise.Status.RESOLVED:
pass
func get_voice_assistant():
return assist_handler

View File

@ -0,0 +1,11 @@
signal on_wake_word(wake_word: String)
signal on_stt_message(message: String)
signal on_tts_message(message: String)
signal on_tts_sound(sound: AudioStreamMP3)
signal on_error()
func start_wakeword() -> bool:
return false
func send_data(data: PackedByteArray) -> void:
pass

View File

@ -11,6 +11,9 @@ var token: String = ""
## If the voice assistant should be enabled
var voice_assistant: bool = false
## If the onboarding process has been completed
var onboarding_complete: bool = false
func _init():
_save_path = "user://settings.json"
@ -19,3 +22,4 @@ func clear():
url = ""
token = ""
voice_assistant = false
onboarding_complete = false

View File

@ -77,8 +77,11 @@ func load_local(path=_save_path):
var save_file = FileAccess.open(path, FileAccess.READ)
# In case that there is no store file yet
if save_file == null:
return false
_loaded = true
on_loaded.emit()
return true
var json_text = save_file.get_as_text()
var save_data = VariantSerializer.parse_value(JSON.parse_string(json_text))