Rev 2 | Rev 9 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2 | Rev 7 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | unit DoorAlarmClientMain; |
1 | unit DoorAlarmClientMain; |
2 | 2 | ||
3 | // TODO: make configurable, which actions should be executed (e.g. run programs) when a motion was detected |
3 | // TODO: make configurable, which actions should be executed (e.g. run programs) when a motion was detected, with different event sounds etc |
- | 4 | // TODO: ask server to subscribe/unsubscribe to events (doorbell, motion) |
|
4 | 5 | ||
5 | interface |
6 | interface |
6 | 7 | ||
7 | uses |
8 | uses |
8 | Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, |
9 | Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, |
9 | Dialogs, HTTPApp, StdCtrls, |
10 | Dialogs, HTTPApp, StdCtrls, |
10 | IdHTTPServer, idContext, idCustomHTTPServer, OleCtrls, SHDocVw, ExtCtrls, |
11 | IdHTTPServer, idContext, idCustomHTTPServer, OleCtrls, SHDocVw, ExtCtrls, |
11 | JPEG, MJPEGDecoderUnit, IniFiles, Menus; |
12 | JPEG, MJPEGDecoderUnit, IniFiles, Menus; |
12 | 13 | ||
13 | type |
14 | type |
- | 15 | TAlarmType = (atUnknown, atMotion, atDoorbell); |
|
- | 16 | ||
14 | TForm1 = class(TForm) |
17 | TForm1 = class(TForm) |
15 | Image1: TImage; |
18 | Image1: TImage; |
16 | TrayIcon1: TTrayIcon; |
19 | TrayIcon1: TTrayIcon; |
17 | PopupMenu1: TPopupMenu; |
20 | PopupMenu1: TPopupMenu; |
18 | Exit1: TMenuItem; |
21 | Exit1: TMenuItem; |
Line 24... | Line 27... | ||
24 | N1: TMenuItem; |
27 | N1: TMenuItem; |
25 | Startalarm1: TMenuItem; |
28 | Startalarm1: TMenuItem; |
26 | N2: TMenuItem; |
29 | N2: TMenuItem; |
27 | Stopalarm1: TMenuItem; |
30 | Stopalarm1: TMenuItem; |
28 | Gotocontrolpanelwebsite1: TMenuItem; |
31 | Gotocontrolpanelwebsite1: TMenuItem; |
- | 32 | doorbellPanel: TPanel; |
|
- | 33 | N3: TMenuItem; |
|
- | 34 | Ignoredoorbell1: TMenuItem; |
|
- | 35 | Ignoremotionalert1: TMenuItem; |
|
- | 36 | unknownAlarm: TPanel; |
|
29 | procedure FormDestroy(Sender: TObject); |
37 | procedure FormDestroy(Sender: TObject); |
30 | procedure FormCreate(Sender: TObject); |
38 | procedure FormCreate(Sender: TObject); |
31 | procedure TrayIcon1Click(Sender: TObject); |
39 | procedure TrayIcon1Click(Sender: TObject); |
32 | procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); |
40 | procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); |
33 | procedure Exit1Click(Sender: TObject); |
41 | procedure Exit1Click(Sender: TObject); |
Line 50... | Line 58... | ||
50 | procedure MotionDetected; |
58 | procedure MotionDetected; |
51 | procedure HandleFrame(Sender: TObject; Frame: TJPEGImage); |
59 | procedure HandleFrame(Sender: TObject; Frame: TJPEGImage); |
52 | procedure WMQueryEndSession(var Message: TWMQueryEndSession); message WM_QUERYENDSESSION; |
60 | procedure WMQueryEndSession(var Message: TWMQueryEndSession); message WM_QUERYENDSESSION; |
53 | procedure StartStream; |
61 | procedure StartStream; |
54 | procedure StopStream; |
62 | procedure StopStream; |
55 | procedure DoShowForm; |
63 | procedure DoShowForm(AlarmType: TAlarmType); |
56 | procedure DoPosition; |
64 | procedure DoPosition; |
57 | procedure StopMusic; |
65 | procedure StopMusic; |
58 | function ControlServerUrl: string; |
66 | function ControlServerUrl: string; |
59 | end; |
67 | end; |
60 | 68 | ||
Line 267... | Line 275... | ||
267 | 275 | ||
268 | MJPEGDecoder := TMJPEGDecoder.Create(Self); |
276 | MJPEGDecoder := TMJPEGDecoder.Create(Self); |
269 | 277 | ||
270 | DoPosition; |
278 | DoPosition; |
271 | 279 | ||
- | 280 | // Question: Should these settings also be saved for the next program session? |
|
272 | Allowmutingsoundinterface1.Checked := ini.ReadBool('Client', 'AllowMute', false); |
281 | Allowmutingsoundinterface1.Checked := ini.ReadBool('Client', 'AllowMute', false); |
- | 282 | Ignoredoorbell1.Checked := ini.ReadBool('Client', 'IgnoreDoorbell', false); |
|
- | 283 | Ignoremotionalert1.Checked := ini.ReadBool('Client', 'IgnoreMotion', false); |
|
273 | 284 | ||
274 | UpdateIPTimerTimer(UpdateIPTimer); |
285 | UpdateIPTimerTimer(UpdateIPTimer); |
275 | UpdateIPTimer.Interval := ini.ReadInteger('Client', 'SubscribeInterval', 30*60) * 1000; |
286 | UpdateIPTimer.Interval := ini.ReadInteger('Client', 'SubscribeInterval', 30*60) * 1000; |
276 | UpdateIPTimer.Enabled := true; |
287 | UpdateIPTimer.Enabled := true; |
277 | end; |
288 | end; |
Line 286... | Line 297... | ||
286 | FreeAndNil(MJPEGDecoder); |
297 | FreeAndNil(MJPEGDecoder); |
287 | end; |
298 | end; |
288 | 299 | ||
289 | procedure TForm1.FormHide(Sender: TObject); |
300 | procedure TForm1.FormHide(Sender: TObject); |
290 | begin |
301 | begin |
- | 302 | if Image2.Visible then |
|
291 | StopStream; |
303 | StopStream; |
292 | end; |
304 | end; |
293 | 305 | ||
294 | procedure TForm1.FormShow(Sender: TObject); |
306 | procedure TForm1.FormShow(Sender: TObject); |
295 | begin |
307 | begin |
- | 308 | if Image2.Visible then |
|
296 | StartStream; |
309 | StartStream; |
297 | end; |
310 | end; |
298 | 311 | ||
299 | procedure TForm1.Gotocontrolpanelwebsite1Click(Sender: TObject); |
312 | procedure TForm1.Gotocontrolpanelwebsite1Click(Sender: TObject); |
300 | begin |
313 | begin |
Line 307... | Line 320... | ||
307 | end; |
320 | end; |
308 | 321 | ||
309 | procedure TForm1.ServerCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); |
322 | procedure TForm1.ServerCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); |
310 | var |
323 | var |
311 | AutoCloseTimerInterval: integer; |
324 | AutoCloseTimerInterval: integer; |
- | 325 | AlarmType: TAlarmType; |
|
312 | begin |
326 | begin |
313 | aResponseInfo.ResponseNo := 200; |
327 | aResponseInfo.ResponseNo := 200; |
314 | aResponseInfo.ContentType := 'text/html'; |
328 | aResponseInfo.ContentType := 'text/html'; |
315 | aResponseInfo.ContentText := ''; |
329 | aResponseInfo.ContentText := ''; |
316 | 330 | ||
Line 341... | Line 355... | ||
341 | begin |
355 | begin |
342 | CloseTimer.Interval := AutoCloseTimerInterval; |
356 | CloseTimer.Interval := AutoCloseTimerInterval; |
343 | CloseTimer.Enabled := true; |
357 | CloseTimer.Enabled := true; |
344 | end; |
358 | end; |
345 | 359 | ||
- | 360 | if ARequestInfo.Params.IndexOf('targets=1.3.6.1.4.1.37476.2.4.2.1002' {camera, motion}) >= 0 then |
|
- | 361 | AlarmType := atMotion |
|
- | 362 | else if ARequestInfo.Params.IndexOf('targets=1.3.6.1.4.1.37476.2.4.2.2001' {sound, doorbell}) >= 0 then |
|
- | 363 | AlarmType := atDoorbell |
|
- | 364 | else |
|
- | 365 | begin |
|
- | 366 | // TODO: Make plugin DLLs ? |
|
- | 367 | AlarmType := atUnknown; |
|
- | 368 | end; |
|
- | 369 | ||
- | 370 | // Attention: Ignoring these events at the client does not prevent the server |
|
- | 371 | // doing other actions (e.g. ask Spotify to stop the music on connected devices) |
|
- | 372 | if Ignoredoorbell1.Checked and (AlarmType = atDoorbell) then Exit; |
|
- | 373 | if Ignoremotionalert1.Checked and (AlarmType = atMotion) then Exit; |
|
- | 374 | ||
- | 375 | if AlarmType = atUnknown then |
|
- | 376 | begin |
|
- | 377 | unknownAlarm.ShowHint := true; |
|
- | 378 | unknownAlarm.Hint := ARequestInfo.Params.Text; |
|
- | 379 | end; |
|
346 | DoShowForm; |
380 | DoShowForm(AlarmType); |
347 | 381 | ||
348 | if ini.ReadBool('Client', 'AutoPopup', true) then |
382 | if ini.ReadBool('Client', 'AutoPopup', true) then |
349 | begin |
383 | begin |
350 | Application.Restore; |
384 | Application.Restore; |
351 | WindowState := wsNormal; |
385 | WindowState := wsNormal; |
Line 367... | Line 401... | ||
367 | begin |
401 | begin |
368 | // TODO: when clicked, the icon-selection won't close |
402 | // TODO: when clicked, the icon-selection won't close |
369 | Application.Restore; |
403 | Application.Restore; |
370 | WindowState := wsNormal; |
404 | WindowState := wsNormal; |
371 | FormStyle := fsNormal; |
405 | FormStyle := fsNormal; |
372 | DoShowForm; |
406 | DoShowForm(atMotion); |
373 | end; |
407 | end; |
374 | 408 | ||
375 | procedure TForm1.UpdateIPTimerTimer(Sender: TObject); |
409 | procedure TForm1.UpdateIPTimerTimer(Sender: TObject); |
376 | var |
410 | var |
377 | lParamList: TStringList; |
411 | lParamList: TStringList; |
Line 383... | Line 417... | ||
383 | lParamList.Add('action=client_subscribe'); // 1.3.6.1.4.1.37476.2.4.1.1 |
417 | lParamList.Add('action=client_subscribe'); // 1.3.6.1.4.1.37476.2.4.1.1 |
384 | lParamList.Add('port='+ini.ReadString('Client', 'ListenPort', '')); |
418 | lParamList.Add('port='+ini.ReadString('Client', 'ListenPort', '')); |
385 | lParamList.Add('ttl='+IntToStr((UpdateIPTimer.Interval div 1000) * 2 + 10)); |
419 | lParamList.Add('ttl='+IntToStr((UpdateIPTimer.Interval div 1000) * 2 + 10)); |
386 | lParamList.Add('targets=1.3.6.1.4.1.37476.2.4.2.0'); // Any |
420 | lParamList.Add('targets=1.3.6.1.4.1.37476.2.4.2.0'); // Any |
387 | lParamList.Add('targets=1.3.6.1.4.1.37476.2.4.2.1002'); // Motion, camera |
421 | lParamList.Add('targets=1.3.6.1.4.1.37476.2.4.2.1002'); // Motion, camera |
- | 422 | lParamList.Add('targets=1.3.6.1.4.1.37476.2.4.2.2001'); // Sound, doorbell |
|
388 | 423 | ||
389 | idhttp := TIdHTTP.Create(nil); |
424 | idhttp := TIdHTTP.Create(nil); |
390 | try |
425 | try |
391 | idhttp.Post(ControlServerUrl, lParamList); |
426 | idhttp.Post(ControlServerUrl, lParamList); |
392 | finally |
427 | finally |
Line 425... | Line 460... | ||
425 | // TODO: user should select in which corner the window show be |
460 | // TODO: user should select in which corner the window show be |
426 | Self.Left := Screen.Width - Self.Width; |
461 | Self.Left := Screen.Width - Self.Width; |
427 | Self.Top := Screen.Height - Self.Height - _TaskBarHeight; |
462 | Self.Top := Screen.Height - Self.Height - _TaskBarHeight; |
428 | end; |
463 | end; |
429 | 464 | ||
430 | procedure TForm1.DoShowForm; |
465 | procedure TForm1.DoShowForm(AlarmType: TAlarmType); |
431 | begin |
466 | begin |
- | 467 | Image1.Visible := AlarmType = atMotion; |
|
- | 468 | Image2.Visible := AlarmType = atMotion; |
|
- | 469 | ||
- | 470 | // BUGBUG! TODO: This does not work. The panels are not visible for some reason! I just get a white window! |
|
- | 471 | doorbellPanel.Visible := AlarmType = atDoorbell; |
|
- | 472 | unknownAlarm.Visible := AlarmType = atUnknown; |
|
- | 473 | ||
432 | if ini.ReadBool('Client', 'AutoReposition', true) then |
474 | if ini.ReadBool('Client', 'AutoReposition', true) then |
433 | begin |
475 | begin |
434 | DoPosition; |
476 | DoPosition; |
435 | end; |
477 | end; |
436 | 478 |