Skip to content

Commit 83cf502

Browse files
authored
Merge pull request #4 from Haydart/connection
Motion sensor incident reporting
2 parents ac18e83 + a4d8060 commit 83cf502

File tree

11 files changed

+79
-48
lines changed

11 files changed

+79
-48
lines changed

app/src/main/java/pl/rmakowiecki/smartalarmcore/AlarmController.kt

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import pl.rmakowiecki.smartalarmcore.extensions.logD
88
import pl.rmakowiecki.smartalarmcore.peripheral.AlarmTriggerPeripheralDevice
99
import pl.rmakowiecki.smartalarmcore.peripheral.camera.CameraPeripheryContract
1010
import pl.rmakowiecki.smartalarmcore.remote.AlarmBackendContract
11-
import pl.rmakowiecki.smartalarmcore.remote.AlarmTriggerReason
12-
import pl.rmakowiecki.smartalarmcore.remote.SecurityIncident
11+
import pl.rmakowiecki.smartalarmcore.remote.models.AlarmTriggerReason
12+
import pl.rmakowiecki.smartalarmcore.remote.models.SecurityIncident
1313
import pl.rmakowiecki.smartalarmcore.setup.UsbSetupProviderContract
1414

1515
class AlarmController(
@@ -55,7 +55,7 @@ class AlarmController(
5555
observeBeamBreakDetector()
5656
observeMotionSensor()
5757
}
58-
else -> {
58+
AlarmArmingState.DISARMED -> {
5959
beamBreakDetectorDisposable.dispose()
6060
motionSensorDisposable.dispose()
6161
}
@@ -70,7 +70,7 @@ class AlarmController(
7070
onNext = {
7171
updateAlarmTriggerState(it)
7272
if (it == TRIGGERED) {
73-
reportBeamBreakIncident()
73+
reportAlarmIncident(AlarmTriggerReason.BEAM_BREAK_DETECTOR)
7474
}
7575
}
7676
)
@@ -83,15 +83,24 @@ class AlarmController(
8383
.registerForChanges()
8484
.applyIoSchedulers()
8585
.subscribeBy(
86-
onNext = { /*logD(it)*/ }
86+
onNext = {
87+
updateAlarmTriggerState(it)
88+
if (it == TRIGGERED) {
89+
reportAlarmIncident(AlarmTriggerReason.MOTION_SENSOR)
90+
}
91+
}
8792
)
8893
}
8994
}
9095

91-
private fun updateAlarmTriggerState(alarmTriggerState: AlarmTriggerState)
92-
= backendInteractor.updateAlarmState(alarmTriggerState)
96+
private fun updateAlarmTriggerState(alarmTriggerState: AlarmTriggerState) = backendInteractor
97+
.updateAlarmState(alarmTriggerState)
98+
.applyIoSchedulers()
99+
.subscribeBy(
100+
onSuccess = { logD("Updating trigger value on server successful") }
101+
)
93102

94-
private fun reportBeamBreakIncident() {
103+
private fun reportAlarmIncident(reason: AlarmTriggerReason) {
95104
val reportTimestamp = System.currentTimeMillis()
96105

97106
val cameraPhotoObservable = camera.capturePhoto()
@@ -100,7 +109,7 @@ class AlarmController(
100109
cameraPhotoObservable.subscribeBy(onNext = { logD("camera photo taken") })
101110

102111
backendInteractor
103-
.reportSecurityIncident(SecurityIncident(AlarmTriggerReason.BEAM_BREAK_DETECTOR, reportTimestamp))
112+
.reportSecurityIncident(SecurityIncident(reason, reportTimestamp))
104113
.flatMapObservable { incidentModel ->
105114
cameraPhotoObservable
106115
.flatMapSingle { (photo, photoNumber) ->

app/src/main/java/pl/rmakowiecki/smartalarmcore/peripheral/camera/CameraPeriphery.kt

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import java.util.*
1919
private const val PHOTO_WIDTH = 1920
2020
private const val PHOTO_HEIGHT = 1080
2121
private const val PHOTO_MAX_COUNT = 10
22-
private const val PHOHOS_IN_SEQUENCE = 10
23-
private const val PHOTO_SEQUENCE_INTERVAL = 250
22+
private const val PHOTOS_IN_SEQUENCE = 10
23+
private const val PHOTO_SEQUENCE_INTERVAL = 250L
2424

2525
class CameraPeriphery(private var context: Context?) : CameraPeripheryContract {
2626

@@ -69,29 +69,26 @@ class CameraPeriphery(private var context: Context?) : CameraPeripheryContract {
6969
override fun onCaptureCompleted(session: CameraCaptureSession?, request: CaptureRequest?, result: TotalCaptureResult?) {
7070
super.onCaptureCompleted(session, request, result)
7171

72-
session?.close()
73-
logD("CaptureSession closed")
72+
logD("picture taken")
73+
74+
if (photosEmittedInSequence < PHOTOS_IN_SEQUENCE) {
75+
Thread.sleep(PHOTO_SEQUENCE_INTERVAL)
76+
triggerImageCapture()
77+
} else {
78+
session?.close()
79+
logD("CaptureSession closed")
80+
}
7481
}
7582
}
7683

7784
private fun triggerImageCapture() {
7885
try {
79-
val captureBuilder = cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG)
86+
val captureBuilder = cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
8087
captureBuilder?.addTarget(imageReadProcessor?.surface)
8188
captureBuilder?.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)
8289

8390
logD("Session initialized.")
8491

85-
val cameraRequests = mutableListOf<CaptureRequest>()
86-
(1..10).map {
87-
val request = cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
88-
request?.addTarget(imageReadProcessor?.surface)
89-
request?.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)
90-
request?.build()
91-
92-
}.forEach { cameraRequests.add(it!!) }
93-
94-
// cameraCaptureSession?.captureBurst(cameraRequests, cameraCaptureCallback, null) CANNOT BE INTERLEAVED
9592
cameraCaptureSession?.capture(captureBuilder?.build(), cameraCaptureCallback, null)
9693
} catch (cameraAccessException: CameraAccessException) {
9794
printStackTrace(cameraAccessException)
@@ -126,7 +123,7 @@ class CameraPeriphery(private var context: Context?) : CameraPeripheryContract {
126123
imageReadProcessor?.setOnImageAvailableListener(
127124
{ reader -> processTakenImage(reader) },
128125
backgroundHandler)
129-
cameraDevice?.createCaptureSession(Collections.singletonList(imageReadProcessor?.surface), cameraSessionCallback, null)
126+
cameraDevice?.createCaptureSession(Collections.singletonList(imageReadProcessor?.surface), cameraSessionCallback, backgroundHandler)
130127
} catch (cameraAccessException: CameraAccessException) {
131128
printStackTrace(cameraAccessException)
132129
}
@@ -154,8 +151,8 @@ class CameraPeriphery(private var context: Context?) : CameraPeripheryContract {
154151
private fun compressTakenImage(imageBytes: ByteArray): ByteArray {
155152
val bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)
156153
val outputStream = ByteArrayOutputStream()
157-
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)
158-
return outputStream.toByteArray()
154+
bitmap?.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)
155+
return outputStream.toByteArray() ?: imageBytes
159156
}
160157

161158
override fun closeCamera() {

app/src/main/java/pl/rmakowiecki/smartalarmcore/remote/AlarmBackendContract.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ import io.reactivex.Single
55
import pl.rmakowiecki.smartalarmcore.AlarmActivity
66
import pl.rmakowiecki.smartalarmcore.AlarmArmingState
77
import pl.rmakowiecki.smartalarmcore.AlarmTriggerState
8+
import pl.rmakowiecki.smartalarmcore.remote.models.SecurityIncident
9+
import pl.rmakowiecki.smartalarmcore.remote.models.SecurityIncidentResponse
810

911
interface AlarmBackendContract {
1012
fun isLoggedInToBackend(): Single<Boolean>
1113
fun signInToBackend(): Single<Boolean>
1214
fun observeAlarmArmingState(): Observable<AlarmArmingState>
13-
fun updateAlarmState(alarmState: AlarmTriggerState)
15+
fun updateAlarmState(alarmState: AlarmTriggerState): Single<Boolean>
1416
fun reportSecurityIncident(securityIncident: SecurityIncident): Single<SecurityIncidentResponse>
1517
fun uploadIncidentPhoto(photoBytes: ByteArray, uniqueIncidentId: String, photoNumber: Int): Single<Boolean>
1618

app/src/main/java/pl/rmakowiecki/smartalarmcore/remote/AlarmBackendInteractor.kt

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ import pl.rmakowiecki.smartalarmcore.AlarmTriggerState
1717
import pl.rmakowiecki.smartalarmcore.extensions.logD
1818
import pl.rmakowiecki.smartalarmcore.extensions.printStackTrace
1919
import pl.rmakowiecki.smartalarmcore.remote.Nodes.ALARM_ARMING
20+
import pl.rmakowiecki.smartalarmcore.remote.Nodes.ALARM_SETTINGS
2021
import pl.rmakowiecki.smartalarmcore.remote.Nodes.ALARM_STATE
2122
import pl.rmakowiecki.smartalarmcore.remote.Nodes.ALARM_TRIGGER
2223
import pl.rmakowiecki.smartalarmcore.remote.Nodes.CORE_DEVICE_DIRECTORY
2324
import pl.rmakowiecki.smartalarmcore.remote.Nodes.IMAGES_DIRECTORY
2425
import pl.rmakowiecki.smartalarmcore.remote.Nodes.PRESENCE_NODE
26+
import pl.rmakowiecki.smartalarmcore.remote.models.*
2527
import pl.rmakowiecki.smartalarmcore.toArmingState
2628

2729
class AlarmBackendInteractor(private val activity: AlarmActivity) : AlarmBackendContract {
@@ -75,8 +77,13 @@ class AlarmBackendInteractor(private val activity: AlarmActivity) : AlarmBackend
7577

7678
databaseNode.child(getCurrentBackendUser()?.uid)
7779
.child(ALARM_STATE)
78-
.setValue(RemoteAlarmStateModel(true, false, true))
79-
.addOnSuccessListener { emitter.onSuccess(true) }
80+
.setValue(RemoteAlarmStateModel.createDefault())
81+
.addOnCompleteListener {
82+
databaseNode.child(getCurrentBackendUser()?.uid)
83+
.child(ALARM_SETTINGS)
84+
.setValue(CameraSequenceSettingsModel.createDefault())
85+
.addOnSuccessListener { emitter.onSuccess(true) }
86+
}
8087
}
8188

8289
override fun isLoggedInToBackend(): Single<Boolean> =
@@ -103,12 +110,12 @@ class AlarmBackendInteractor(private val activity: AlarmActivity) : AlarmBackend
103110
}
104111
}
105112

106-
override fun updateAlarmState(alarmState: AlarmTriggerState) {
113+
override fun updateAlarmState(alarmState: AlarmTriggerState): Single<Boolean> = Single.create { emitter ->
107114
databaseNode.child(getCurrentBackendUser()?.uid)
108115
.child(ALARM_STATE)
109116
.child(ALARM_TRIGGER)
110117
.setValue(alarmState.toBoolean())
111-
.addOnCompleteListener { }
118+
.addOnCompleteListener { emitter.onSuccess(it.isSuccessful) }
112119
}
113120

114121
override fun reportSecurityIncident(securityIncident: SecurityIncident): Single<SecurityIncidentResponse> = Single.create { emitter ->
@@ -126,7 +133,6 @@ class AlarmBackendInteractor(private val activity: AlarmActivity) : AlarmBackend
126133
}
127134

128135
override fun uploadIncidentPhoto(photoBytes: ByteArray, uniqueIncidentId: String, photoNumber: Int): Single<Boolean> = Single.create { emitter ->
129-
130136
storageNode.child(CORE_DEVICE_DIRECTORY)
131137
.child(IMAGES_DIRECTORY)
132138
.child(getCurrentBackendUser()?.uid ?: "non_assignable_incidents")
@@ -136,15 +142,4 @@ class AlarmBackendInteractor(private val activity: AlarmActivity) : AlarmBackend
136142
}
137143
}
138144

139-
private fun DataSnapshot.getArmingState() = (this.value as Boolean).toArmingState()
140-
141-
class RemoteAlarmStateModel(
142-
val active: Boolean,
143-
val triggered: Boolean,
144-
val connected: Boolean
145-
)
146-
147-
class SecurityIncidentResponse(
148-
val isSuccessful: Boolean,
149-
val generatedId: String
150-
)
145+
private fun DataSnapshot.getArmingState() = (this.value as Boolean).toArmingState()

app/src/main/java/pl/rmakowiecki/smartalarmcore/remote/Constants.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ object Nodes {
44
const val ALARM_TRIGGER = "triggered"
55
const val ALARM_ARMING = "active"
66
const val ALARM_STATE = "state"
7+
const val ALARM_SETTINGS = "settings"
78
const val CORE_DEVICE_DIRECTORY = "core_assets"
89
const val IMAGES_DIRECTORY = "images"
910
const val INCIDENTS = "incidents"

app/src/main/java/pl/rmakowiecki/smartalarmcore/remote/AlarmTriggerReason.kt renamed to app/src/main/java/pl/rmakowiecki/smartalarmcore/remote/models/AlarmTriggerReason.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package pl.rmakowiecki.smartalarmcore.remote
1+
package pl.rmakowiecki.smartalarmcore.remote.models
22

33
enum class AlarmTriggerReason {
44
BEAM_BREAK_DETECTOR,
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package pl.rmakowiecki.smartalarmcore.remote.models
2+
3+
class CameraSequenceSettingsModel(
4+
val sessionPhotoCount: Int,
5+
val photoSequenceIntervalMillis: Int) {
6+
7+
companion object {
8+
fun createDefault() = CameraSequenceSettingsModel(20, 250)
9+
}
10+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package pl.rmakowiecki.smartalarmcore.remote.models
2+
3+
class RemoteAlarmStateModel(
4+
val active: Boolean,
5+
val triggered: Boolean,
6+
val connected: Boolean) {
7+
8+
companion object {
9+
fun createDefault() = RemoteAlarmStateModel(true, false, true)
10+
}
11+
}

app/src/main/java/pl/rmakowiecki/smartalarmcore/remote/RemoteSecurityIncident.kt renamed to app/src/main/java/pl/rmakowiecki/smartalarmcore/remote/models/RemoteSecurityIncident.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package pl.rmakowiecki.smartalarmcore.remote
1+
package pl.rmakowiecki.smartalarmcore.remote.models
22

33
class RemoteSecurityIncident private constructor(
44
val reason: AlarmTriggerReason,

app/src/main/java/pl/rmakowiecki/smartalarmcore/remote/SecurityIncident.kt renamed to app/src/main/java/pl/rmakowiecki/smartalarmcore/remote/models/SecurityIncident.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package pl.rmakowiecki.smartalarmcore.remote
1+
package pl.rmakowiecki.smartalarmcore.remote.models
22

33
class SecurityIncident(
44
val reason: AlarmTriggerReason,

0 commit comments

Comments
 (0)