Skip to content

Commit 302766d

Browse files
authored
feat: add stagehand fields [PPT-2370] (#306)
1 parent 2049f7b commit 302766d

7 files changed

Lines changed: 90 additions & 3 deletions

File tree

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ services:
1717
PG_DATABASE_URL: ${PG_DATABASE_URL:-postgresql://postgres:password@postgres:5432/model_dev}
1818

1919
postgres:
20-
image: postgres:17-alpine
20+
image: postgres:18-alpine
2121
healthcheck:
2222
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
2323
interval: 30s
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-- +micrate Up
2+
-- SQL in section 'Up' is executed when this migration is applied
3+
4+
ALTER TABLE "sys" ADD COLUMN IF NOT EXISTS camera_snapshot_urls TEXT[] DEFAULT '{}';
5+
UPDATE "sys" SET camera_snapshot_urls[1] = camera_snapshot_url WHERE camera_snapshot_url IS NOT NULL;
6+
7+
ALTER TABLE "driver" ADD COLUMN IF NOT EXISTS alert_level public.alert_severity NOT NULL DEFAULT 'MEDIUM'::public.alert_severity;
8+
ALTER TABLE "mod" ADD COLUMN IF NOT EXISTS alert_level public.alert_severity NOT NULL DEFAULT 'MEDIUM'::public.alert_severity;
9+
10+
-- +micrate Down
11+
-- SQL section 'Down' is executed when this migration is rolled back
12+
13+
ALTER TABLE "driver" DROP COLUMN IF EXISTS alert_level;
14+
ALTER TABLE "mod" DROP COLUMN IF EXISTS alert_level;
15+
ALTER TABLE "sys" DROP COLUMN IF EXISTS camera_snapshot_urls;

spec/control_system_spec.cr

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,26 @@ module PlaceOS::Model
169169
end
170170
end
171171

172+
describe "camera_snapshot_urls" do
173+
it "setting camera_snapshot_url updates camera_snapshot_urls" do
174+
control_system = Generator.control_system
175+
control_system.camera_snapshot_url = "https://placeos.com/"
176+
control_system.save!
177+
control_system.reload!
178+
control_system.camera_snapshot_urls[0]?.should eq control_system.camera_snapshot_url
179+
control_system.destroy
180+
end
181+
182+
it "setting camera_snapshot_urls updates camera_snapshot_url" do
183+
control_system = Generator.control_system
184+
control_system.camera_snapshot_urls = ["https://placeos.com/"]
185+
control_system.save!
186+
control_system.reload!
187+
control_system.camera_snapshot_url.should eq control_system.camera_snapshot_urls[0]
188+
control_system.destroy
189+
end
190+
end
191+
172192
describe "remove_module" do
173193
it "removes a module if present" do
174194
control_system = Generator.control_system

src/placeos-models/control_system.cr

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ module PlaceOS::Model
4848
attribute support_url : String = ""
4949
attribute timetable_url : String? # The timetable visualisation
5050
attribute camera_snapshot_url : String? # snapshot images of the room
51-
attribute camera_url : String? # admin control
51+
attribute camera_snapshot_urls : Array(String) = -> { [] of String }
52+
attribute camera_url : String? # admin control
5253

5354
# if not bookable via google / O365 calendaring systems
5455
attribute room_booking_url : String?
@@ -110,10 +111,49 @@ module PlaceOS::Model
110111

111112
# Validate support URI
112113
validate ->(this : ControlSystem) {
114+
if url = this.camera_snapshot_url
115+
this.validation_error(:camera_snapshot_url, "is an invalid URI") unless Validation.valid_uri?(url)
116+
end
117+
118+
this.camera_snapshot_urls.each do |url|
119+
if !Validation.valid_uri?(url)
120+
this.validation_error(:camera_snapshot_urls, "contains an invalid URI")
121+
break
122+
end
123+
end
124+
113125
return if this.support_url.blank?
114126
this.validation_error(:support_url, "is an invalid URI") unless Validation.valid_uri?(this.support_url)
115127
}
116128

129+
before_save :unique_camera_urls
130+
131+
def unique_camera_urls
132+
update_camera_urls
133+
unique_urls = self.camera_snapshot_urls.uniq
134+
if unique_urls.size != self.camera_snapshot_urls.size
135+
self.camera_snapshot_urls = unique_urls
136+
end
137+
end
138+
139+
def update_camera_urls
140+
url = camera_snapshot_url
141+
if camera_snapshot_urls.size == 1 && url && !@camera_snapshot_urls_changed && @camera_snapshot_url_changed
142+
self.camera_snapshot_urls[0] = url
143+
@camera_snapshot_urls_changed = true
144+
elsif url && camera_snapshot_urls.empty?
145+
camera_snapshot_urls.insert(0, url)
146+
@camera_snapshot_urls_changed = true
147+
end
148+
self.camera_snapshot_url = camera_snapshot_urls.first?
149+
end
150+
151+
def camera_snapshot_urls=(vals : Array(String))
152+
@camera_snapshot_urls = vals
153+
@camera_snapshot_urls_changed = true
154+
vals
155+
end
156+
117157
# Queries
118158
###############################################################################################
119159

src/placeos-models/driver.cr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ module PlaceOS::Model
3333

3434
attribute role : Role, es_type: "integer", converter: Enum::ValueConverter(PlaceOS::Model::Driver::Role)
3535

36+
attribute alert_level : Alert::Severity = Alert::Severity::MEDIUM, converter: PlaceOS::Model::PGEnumConverter(PlaceOS::Model::Alert::Severity),
37+
description: "the default alert level for stagehand issues"
38+
3639
# Path to driver, relative to repository directory
3740
attribute file_name : String
3841

src/placeos-models/module.cr

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ module PlaceOS::Model
3232
# Cache the module's driver role locally for load order
3333
attribute role : Driver::Role, es_type: "integer", converter: Enum::ValueConverter(PlaceOS::Model::Driver::Role)
3434

35+
attribute alert_level : Alert::Severity?, converter: PlaceOS::Model::PGEnumConverter(PlaceOS::Model::Alert::Severity),
36+
description: "the alert level for stagehand issues"
37+
3538
# Connected state in model so we can filter and search on it
3639
attribute connected : Bool = true
3740
attribute running : Bool = false
@@ -228,6 +231,8 @@ module PlaceOS::Model
228231
# NOTE: Temporary while `edge` feature developed
229232
before_create :set_edge_hint
230233

234+
before_create :set_alert_level
235+
231236
# Logic modules are automatically added to the ControlSystem
232237
#
233238
protected def add_logic_module
@@ -275,6 +280,10 @@ module PlaceOS::Model
275280
end
276281
end
277282

283+
protected def set_alert_level
284+
self.alert_level = driver.try(&.alert_level) || Alert::Severity::MEDIUM if self.alert_level.nil?
285+
end
286+
278287
# Overridden attribute accessors
279288
###############################################################################################
280289

src/placeos-models/utilities/id_generator.cr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class PlaceOS::Model::Utilities::IdGenerator
4747

4848
# Provides a channel with an infinite stream of psuedo-random values up to
4949
# *max* size and a guaranteed cycle of at least *max* samples.
50-
private def self.seq(max = UInt32::MAX, r = Random::DEFAULT)
50+
private def self.seq(max = UInt32::MAX, r = Random.new)
5151
ch = Channel(UInt32).new
5252
spawn do
5353
loop do

0 commit comments

Comments
 (0)