يتم تنفيذ نوع الجهاز "الكاميرا" باستخدام سمتَين:
PushAvStreamTransportTrait،
التي تتعامل مع نقل بث الصوت والفيديو باستخدام بروتوكولات مستندة إلى الإرسال،
وWebRtcLiveViewTrait،
التي تتيح التحكّم في البث المباشر ووظيفة "التحدث المباشر".
يجب دائمًا التحقّق من توفّر السمات والأوامر لجهاز معيّن قبل استخدام أي ميزات أو محاولة تعديل السمات. لمزيد من المعلومات، اطّلِع على مقالة التحكّم في الأجهزة على iOS.
| نوع الجهاز في Home APIs | السمات | تطبيق Swift النموذجي | حالة الاستخدام |
|---|---|---|---|
|
الكاميرا
جهاز يلتقط صورًا ثابتة أو فيديوهات قد تتضمّن الكاميرات بثًا مباشرًا يسهل الوصول إليه أو ميزة "التحدّث والاستماع" أو أحداث الرصد. |
السمات المطلوبة google PushAvStreamTransportTrait google WebRtcLiveViewTrait |
الكاميرا |
الحصول على معلومات أساسية عن جهاز
تتضمّن السمة BasicInformation معلومات، مثل اسم المورّد ومعرّف المورّد ومعرّف المنتج واسم المنتج (يتضمّن معلومات الطراز) وإصدار البرنامج والرقم التسلسلي للجهاز:
// [START get_device_information] let vendorName = basicInfoTrait.attributes.vendorName! let vendorID = basicInfoTrait.attributes.vendorID! let productID = basicInfoTrait.attributes.productID! let productName = basicInfoTrait.attributes.productName! let softwareVersion = basicInfoTrait.attributes.softwareVersion! let serialNumber = basicInfoTrait.attributes.serialNumber! // [END get_device_information]
التحقّق من إمكانية اتصال جهاز
يتم التحقّق من إمكانية الاتصال بجهاز على مستوى نوع الجهاز، لأنّ بعض الأجهزة تتوافق مع أنواع أجهزة متعددة. الحالة التي يتم عرضها هي مزيج من حالات الاتصال لجميع السمات على هذا الجهاز.
let lightConnectivity = dimmableLightDeviceType.metadata.sourceConnectivity .connectivityState
قد يتم رصد حالة partiallyOnline في حال استخدام أنواع أجهزة مختلطة
عندما لا يتوفّر اتصال بالإنترنت. قد تظل سمات Matter Standard
متوفرة على الإنترنت بسبب التوجيه المحلي، ولكن ستكون السمات المستندة إلى السحابة الإلكترونية غير متوفرة.
بدء بث مباشر
لبدء بث مباشر، أرسِل سلسلة Session Description Protocol (SDP) إلى طريقة startLiveView(offerSdp:) في السمة WebRtcLiveViewTrait، والتي تعرض ثلاث قيم:
- تمثّل هذه السمة وصف بروتوكول الجلسة (SDP) للجلسة.
- مدة الجلسة بالثواني
- رقم تعريف الجلسة الذي يمكن استخدامه لتمديد الجلسة أو إنهاءها
public func sendOffer(offerSdp: String) async throws
-> (answerSdp: String, mediaSessionId: String, liveViewDuration: TimeInterval)
{
do {
// Sending StartLiveView command
let response = try await liveViewTrait.startLiveView(
offerSdp: offerSdp
)
// Received StartLiveView response
return (
answerSdp: response.answerSdp,
mediaSessionId: response.mediaSessionId,
liveViewDuration: TimeInterval(response.liveSessionDurationSeconds)
)
} catch {
// Failed to send StartLiveView command
throw error
}
}
تمديد مدة بث مباشر
تتضمّن أحداث البث المباشر مدة محددة مسبقًا تنتهي بعدها صلاحيتها. لتمديد مدة بث نشط، أرسِل طلب تمديد باستخدام طريقة extendLiveView(mediaSessionId:optionalArgsProvider:):
public func extendLiveView(mediaSessionId: String) async throws {
do {
// Extending live view
let extendedDuration = try await liveViewTrait.extendLiveView(mediaSessionId: mediaSessionId)
} catch {
// Failed to extend live view
throw error
}
}
بدء TalkBack وإيقافه
لبدء TalkBack، استدعِ طريقة startTalkback(mediaSessionId:optionalArgsProvider:) في السمة WebRtcLiveViewTrait.
لإيقاف التسجيل، استخدِم stopTalkback(mediaSessionId:).
public func toggleTwoWayTalk(isOn: Bool, mediaSessionId: String) async throws {
do {
if isOn {
try await liveViewTrait.startTalkback(mediaSessionId: mediaSessionId)
} else {
try await liveViewTrait.stopTalkback(mediaSessionId: mediaSessionId)
}
} catch {
throw HomeError.commandFailed("Failed to toggle twoWayTalk: \(error)")
}
}
تفعيل ميزة التسجيل وإيقافها
لتفعيل إمكانية التسجيل في الكاميرا، يجب تمرير
TransportStatusEnum.Active
إلى
طريقة
setTransportStatus(transportStatus:optionalArgsProvider:)
في السمة
PushAvStreamTransportTrait. لإيقاف إمكانية التسجيل، مرِّر القيمة
TransportStatusEnum.Inactive.
في المثال التالي، نضمّن هذه المكالمات في مكالمة واحدة تستخدم Boolean لتبديل إمكانية التسجيل:
public func toggleIsRecording(isOn: Bool) {
self.uiState = .loading
guard let pushAvStreamTransportTrait else {
// PushAvStreamTransportTrait not found.
return
}
Task {
do {
try await pushAvStreamTransportTrait.setTransportStatus(
transportStatus: isOn ? .active : .inactive)
if isOn {
do {
self.player = try self.createWebRtcPlayer()
} catch {
// Failed to initialize WebRtcPlayer
self.uiState = .disconnected
return
}
await self.player?.initialize()
self.uiState = .live
} else {
self.player = nil
self.uiState = .off
}
} catch {
// Failed to toggle onOff
}
}
}
إنّ تفعيل ميزة التسجيل في الكاميرا أو إيقافها هو نفسه تشغيل فيديو الكاميرا أو إيقافه. وعندما يكون فيديو الكاميرا مفعّلاً، يتم التسجيل (لأغراض الأحداث والمقاطع ذات الصلة).
عندما تكون إمكانية التسجيل غير مفعَّلة (يكون فيديو الكاميرا متوقفًا):
- سيظل بإمكان الكاميرا الظهور على أنّها متصلة بالإنترنت وفقًا
connectivityStateلنوع الجهاز. - لا يمكن الوصول إلى البث المباشر، ولا ترصد الكاميرا أي أحداث على السحابة الإلكترونية.
التحقّق من تفعيل إمكانية التسجيل
لتحديد ما إذا كانت إمكانية التسجيل في الكاميرا مفعَّلة، تحقَّق مما إذا كان أي من عمليات الربط نشطًا. يحدّد المثال التالي دالتَين لإجراء ذلك:
public func isDeviceRecording() -> Bool {
guard let pushAvStreamTransportTrait else {
// PushAvStreamTransportTrait not found.
return false
}
guard
let hasActiveConnection =
pushAvStreamTransportTrait
.attributes
.currentConnections?
.contains(where: { $0.transportStatus == .active })
else {
return false
}
return hasActiveConnection
}
إعدادات البطارية
يمكن التحكّم في إعدادات البطارية المختلفة من خلال واجهات برمجة التطبيقات Home.
ضبط إعدادات استخدام البطارية المفضَّلة
يتيح لك ضبط توازن الطاقة إمكانية تحديد المفاضلة بين عمر البطارية والأداء لجهاز معيّن. يمكنك إنشاء ملفات شخصية مختلفة للبطارية، مثل "موسّع" و"متوازن" و "أداء"، والتبديل بينها.
يتم تنفيذ هذه الميزة من خلال تعديل السمة
currentEnergyBalance
في السمة EnergyPreference. تقبل السمة فهرسًا صحيحًا
يتوافق مع ملف شخصي محدّد في قائمة energyBalances الخاصة بالجهاز (على سبيل المثال، 0 لـ EXTENDED،
1 لـ BALANCED، و2 لـ PERFORMANCE).
تشير القيمة null في currentEnergyBalance إلى أنّ الجهاز يستخدم ملفًا شخصيًا مخصّصًا. هذه حالة للقراءة فقط.
يوضّح ما يلي مثالاً على بنية ستستخدمها السمة currentEnergyBalance، يليه مقتطف الرمز الفعلي الذي يستخدم السمة.
// Example energyBalances list { "energy_balances": [ { "step": 0, "label": "EXTENDED" }, { "step": 50, "label": "BALANCED" }, { "step": 100, "label": "PERFORMANCE" } ] }
private func setBatteryUsage(to option: UInt8) async throws { _ = try await energyPreferenceTrait.update { $0.setCurrentEnergyBalance(option) } }
تفعيل ميزة "توفير شحن البطارية تلقائيًا"
لضبط هذه الميزة، عدِّل السمة
currentLowPowerModeSensitivity الخاصة بالسمة EnergyPreference. تستخدم هذه السمة فهرسًا لاختيار مستوى حساسية، حيث يمثّل 0 عادةً Disabled، ويمثّل 1 Enabled أو Automatic.
private func setAutoBatterySaver(to value: Bool) async throws { _ = try await energyPreferenceTrait.update { $0.setCurrentLowPowerModeSensitivity(value ? 1 : 0) } }
الحصول على حالة شحن البطارية
للحصول على حالة الشحن الحالية للجهاز (جارٍ الشحن أو مشحون بالكامل أو لا يتم الشحن)، استخدِم السمة batChargeState الخاصة بسمة PowerSource.
self.chargingState = powerSourceTrait.attributes.batChargeState var description: String switch self.chargingState { case .isCharging: description = "Charging" case .isAtFullCharge: description = "Full" case .isNotCharging: description = "Not Charging" default: description = "Unknown" }
الحصول على مستوى البطارية
للحصول على مستوى شحن البطارية الحالي، استخدِم السمة
batChargeLevel
الخاصة بالسمة
PowerSource. يكون المستوى إما OK أو Warning (منخفض) أو Critical.
self.batteryLevel = powerSourceTrait.attributes.batChargeLevel var description: String switch self.batteryLevel { case .ok: description = "OK" case .warning: description = "Warning" case .critical: description = "Critical" default: description = "Unknown" }
الحصول على مصدر الطاقة
لتحديد مصدر الطاقة الذي يستخدمه الجهاز، استخدِم السمتَين BatPresent وwiredPresent من السمة PowerSource.
if powerSourceTrait.attributes.wiredPresent ?? false { self.powerSourceType = .wired } else if powerSourceTrait.attributes.batPresent ?? false { self.powerSourceType = .battery } else { self.powerSourceType = nil }
إعدادات الصوت
يمكن التحكّم في إعدادات الصوت المختلفة من خلال واجهات برمجة التطبيقات Home.
تفعيل الميكروفون أو إيقافه
لتفعيل ميكروفون الجهاز أو إيقافه، عدِّل السمة
microphoneMuted
لسمة CameraAvStreamManagementTrait باستخدام الدالة المضمّنة
setMicrophoneMuted:
// Turn the device's microphone on or off
func setMicrophone(on: Bool) async {
do {
_ = try await self.cameraAvStreamManagementTrait?.update {
$0.setMicrophoneMuted(!on)
}
} catch {
// Error
}
}
تفعيل التسجيل الصوتي أو إيقافه
لتفعيل تسجيل الصوت أو إيقافه على الجهاز، عدِّل السمة
recordingMicrophoneMuted
في السمة CameraAvStreamManagementTrait باستخدام الدالة المضمّنة
setRecordingMicrophoneMuted:
// Turn audio recording on or off for the device
func setAudioRecording(on: Bool) async {
do {
_ = try await self.cameraAvStreamManagementTrait?.update {
$0.setRecordingMicrophoneMuted(!on)
}
} catch {
// Error
}
}
ضبط مستوى صوت مكبّر الصوت
لضبط مستوى صوت مكبّر الصوت للجهاز، عدِّل السمة
speakerVolumeLevel
في السمة CameraAvStreamManagementTrait باستخدام الدالة المضمّنة
setSpeakerVolumeLevel:
// Adjust the camera speaker volume
func setSpeakerVolume(to value: UInt8) async {
do {
_ = try await cameraAvStreamManagementTrait.update {
$0.setSpeakerVolumeLevel(value)
}
} catch {
// Error
}
}
إعدادات أخرى
يمكن التحكّم في إعدادات أخرى متنوعة من خلال واجهات برمجة التطبيقات الخاصة بالمنزل الذكي.
تغيير اتجاه الصورة
يمكن تدوير اتجاه صورة الكاميرا (الفيديو). يمكن تدوير الفيديو بمقدار 180 درجة فقط.
لتغيير اتجاه صورة الكاميرا، عدِّل السمة
imageRotation
لسمة CameraAvStreamManagementTrait باستخدام الدالة المضمّنة
setImageRotation:
// Change the camera's image orientation
// Value must be 0 or 180
func setImageRotation(to value: UInt16) async {
do {
_ = try await cameraAvStreamManagementTrait.update {
$0.setImageRotation(value)
}
} catch {
// Error
}
}
تفعيل ميزة "الرؤية الليلية" أو إيقافها
لتفعيل ميزة "الرؤية الليلية" أو إيقافها للكاميرا، استخدِم TriStateAutoEnum
لتعديل
السمة nightVision
للسمة CameraAvStreamManagementTrait باستخدام الدالة المضمّنة
setNightVision:
// Turn night vision on or off
func setNightVision(
to value: Google.CameraAvStreamManagementTrait.TriStateAutoEnum
) async {
do {
_ = try await cameraAvStreamManagementTrait.update {
$0.setNightVision(value)
}
} catch {
// Error
}
}
تغيير سطوع مؤشر LED للحالة
لتغيير مستوى سطوع مؤشر LED الخاص بالحالة، استخدِم
ThreeLevelAutoEnum
لتعديل
السمة statusLightBrightness
لسمة CameraAvStreamManagementTrait باستخدام الدالة المضمّنة
setStatusLightBrightness:
// Set the LED brightness
func setStatusLightBrightness(
to value: Google.CameraAvStreamManagementTrait.ThreeLevelAutoEnum
) async {
do {
_ = try await cameraAvStreamManagementTrait.update {
$0.setStatusLightBrightness(value)
}
} catch {
// Error
}
}
تغيير إطار عرض الكاميرا
منظر الكاميرا هو نفسه ميزة "التكبير والقص" الموضّحة في مقالة الدعم تكبير فيديو كاميرا Nest وتحسينه.
يتم تحديد إطار العرض في ViewportStruct يحتوي على أربع قيم تُستخدَم كإحداثيات لإطار العرض. يتم تحديد الإحداثيات على النحو التالي:
(x1,y1) -- (x2,y1) | | (x1,y2) -- (x2,y2)
يعتمد تحديد قيم ViewportStruct على واجهة مستخدم التطبيق وطريقة تنفيذ الكاميرا. على مستوى أساسي جدًا، لضبط إطار العرض لفيديو الكاميرا، عدِّل السمة viewport الخاصة بالسمة CameraAvStreamManagementTrait باستخدام ViewportStruct، وذلك باستخدام الدالة المضمّنة setViewport.
func setCrop(x1: UInt16, y1: UInt16, x2: UInt16, y2: UInt16) {
let viewport = Google.CameraAvStreamManagementTrait.ViewportStruct(
x1: x1,
y1: y1,
x2: x2,
y2: y2
)
Task {
do {
try await cameraAvStreamManagementTrait.update {
$0.setViewport(viewport)
}
} catch {
// Error
}
}
}
إنشاء TransportOptionsStruct
تتطلّب بعض الإعدادات تعديلات على الخصائص في TransportOptionsStruct،
والتي يتم تمريرها بعد ذلك إلى خيارات النقل الخاصة باتصال البث. بالنسبة إلى Swift، يجب إنشاء هذا البنية قبل تعديل أي سمات.
استخدِم دالة المساعدة هذه لإنشاء البنية لاستخدامها مع تغييرات الإعدادات التالية:
func getTransportOptions(
transportOptions: Google.PushAvStreamTransportTrait.TransportOptionsStruct,
wakeUpSensitivity: UInt8?,
maxEventLength: UInt32?
) async throws
-> Google.PushAvStreamTransportTrait.TransportOptionsStruct
{
var newMotionTimeControl:
Google.PushAvStreamTransportTrait.TransportMotionTriggerTimeControlStruct? = nil
if let maxEventLength {
guard let motionTimeControl = transportOptions.triggerOptions.motionTimeControl else {
throw HomeError.failedPrecondition(
// Error - cannot update max event length without motion time control
}
newMotionTimeControl =
Google.PushAvStreamTransportTrait.TransportMotionTriggerTimeControlStruct(
initialDuration: motionTimeControl.initialDuration,
augmentationDuration: motionTimeControl.augmentationDuration,
maxDuration: maxEventLength,
blindDuration: motionTimeControl.blindDuration
)
}
return Google.PushAvStreamTransportTrait.TransportOptionsStruct(
streamUsage: .recording,
videoStreamID: nil,
audioStreamID: nil,
tlsEndpointID: transportOptions.tlsEndpointID,
url: transportOptions.url,
triggerOptions: Google.PushAvStreamTransportTrait.TransportTriggerOptionsStruct(
triggerType: .motion,
motionZones: nil,
motionSensitivity: wakeUpSensitivity,
motionTimeControl: newMotionTimeControl,
maxPreRollLen: nil
),
ingestMethod: .cmafIngest,
containerOptions: Google.PushAvStreamTransportTrait.ContainerOptionsStruct(
containerType: .cmaf,
cmafContainerOptions: nil
),
expiryTime: nil
)
}
private func getRecordingConnection() async throws
-> Google.PushAvStreamTransportTrait.TransportConfigurationStruct?
{
guard let pushAvStreamTransportTrait else {
// Error - PushAvStreamTransport trait not available
return nil
}
let connections = try await pushAvStreamTransportTrait.findTransport().transportConfigurations
for connection in connections {
guard let transportOptions = connection.transportOptions,
transportOptions.streamUsage == .recording
else {
continue
}
return connection
}
return nil
}
ضبط حساسية أجهزة الاستشعار لتشغيل الكاميرا
يتم استخدام حساسية التنشيط في الجهاز للحفاظ على البطارية من خلال تقليل النطاق الذي يمكن للجهاز من خلاله استشعار النشاط وزيادة الوقت اللازم لتنشيط الجهاز بعد رصد هذا النشاط.
في واجهات برمجة التطبيقات الخاصة بالمنزل، يمكن ضبط هذا الإعداد باستخدام السمة motionSensitivity الخاصة بـ triggerOptions في transportOptions الخاص بالجهاز. يتم تحديد هذه الخيارات ضمن السمة PushAvStreamTransportTrait لكل جهاز.
لا يمكن ضبط حساسية التنشيط إلا على القيم التالية:
- 1 = منخفض
- 5 = متوسط
- 10 = مرتفع
تتم عملية التعديل من خلال العثور على إعدادات النقل لجداول التسجيل النشطة باستخدام الأمر
findTransport، ثم تعديل الإعدادات باستخدام قيمة الحساسية الجديدة باستخدام الأمر
modifyPushTransport.
يتطلّب الأمر modifyPushTransport تمرير TransportOptionsStruct الكامل، لذا عليك أولاً نسخ القيم الحالية من الإعداد الحالي. اطّلِع على إنشاء TransportOptionsStruct لدالة مساعدة لإجراء ذلك.
func setWakeUpSensitivity(to value: UInt8) async {
do {
let connection = try await getRecordingConnection()
guard let connection,
let transportOptions = connection.transportOptions
else {
// Error - Transport options not available
return
}
guard transportOptions.triggerOptions.motionSensitivity != nil else {
// Error - Motion sensitivity not available to be updated for this device
return
}
try await pushAvStreamTransportTrait.modifyPushTransport(
connectionID: connection.connectionID,
transportOptions: self.getTransportOptions(
transportOptions: transportOptions,
wakeUpSensitivity: value,
maxEventLength: nil
)
)
} catch {
// Error
}
}
تعديل المدة القصوى للحدث
الحد الأقصى لمدة الحدث هو المدة الزمنية التي ستسجّل فيها الكاميرا مقطع فيديو خاصًا بحدث معيّن. يمكن ضبط ذلك من خلال واجهات برمجة التطبيقات Home، لكل جهاز، على المدد نفسها التي يمكن ضبطها من خلال Google Home app (GHA)، وذلك بفواصل زمنية بالثواني:
- 10 ثوانٍ
- 15 ثانية
- 30 ثانية
- 60 ثانية (دقيقة واحدة)
- 120 ثانية (دقيقتان)
- 180 ثانية (3 دقائق)
في واجهات برمجة التطبيقات الخاصة بالمنزل، يمكن ضبط هذا الإعداد باستخدام السمة motionTimeControl الخاصة بـ triggerOptions في transportOptions الخاص بالجهاز. يتم تحديد هذه الخيارات ضمن السمة PushAvStreamTransportTrait لكل جهاز.
تتم عملية التعديل من خلال العثور على إعدادات النقل لجداول التسجيل النشطة باستخدام الأمر findTransport، ثم تعديل الإعدادات باستخدام قيمة طول الحدث الجديدة باستخدام الأمر modifyPushTransport.
يتطلّب الأمر modifyPushTransport تمرير TransportOptionsStruct الكامل، لذا عليك أولاً نسخ القيم الحالية من الإعداد الحالي. اطّلِع على إنشاء TransportOptionsStruct لدالة مساعدة لإجراء ذلك.
func setMaxEventLength(to value: UInt32) async {
do {
let connection = try await getRecordingConnection()
guard let connection,
let transportOptions = connection.transportOptions
else {
// Error - Transport options not available
return
}
guard transportOptions.triggerOptions.motionTimeControl != nil else {
// Error - Motion time control not available to be updated for this device
return
}
try await pushAvStreamTransportTrait.modifyPushTransport(
connectionID: connection.connectionID,
transportOptions: self.getTransportOptions(
transportOptions: transportOptions,
wakeUpSensitivity: nil,
maxEventLength: value
)
)
} catch {
// Error
}
}