MythTV master
zmclient.cpp
Go to the documentation of this file.
1/*
2 zmclient.cpp
3*/
4
5// C++
6#include <unistd.h>
7
8// qt
9#include <QTimer>
10
11//MythTV
17
18//zoneminder
19#include "zmclient.h"
20#include "zmminiplayer.h"
21
22// the protocol version we understand
23static constexpr const char* ZM_PROTOCOL_VERSION { "11" };
24
26 : QObject(nullptr),
27 m_retryTimer(new QTimer(this))
28{
29 setObjectName("ZMClient");
31
33}
34
36
38{
39 if (!m_zmclient)
40 m_zmclient = new ZMClient;
41 return m_zmclient;
42}
43
45{
46 QString zmserver_host;
47
48 zmserver_host = gCoreContext->GetSetting("ZoneMinderServerIP", "");
49 int zmserver_port = gCoreContext->GetNumSetting("ZoneMinderServerPort", -1);
50
51 // don't try to connect if we don't have a valid host or port
52 if (zmserver_host.isEmpty() || zmserver_port == -1)
53 {
54 LOG(VB_GENERAL, LOG_INFO, "ZMClient: no valid IP or port found for mythzmserver");
55 return false;
56 }
57
58 return ZMClient::get()->connectToHost(zmserver_host, zmserver_port);
59}
60
61bool ZMClient::connectToHost(const QString &lhostname, unsigned int lport)
62{
63 QMutexLocker locker(&m_socketLock);
64
65 m_hostname = lhostname;
66 m_port = lport;
67
68 m_bConnected = false;
69 int count = 0;
70 while (count < 2 && !m_bConnected)
71 {
72 ++count;
73
74 LOG(VB_GENERAL, LOG_INFO,
75 QString("Connecting to zm server: %1:%2 (try %3 of 2)")
76 .arg(m_hostname).arg(m_port).arg(count));
77 if (m_socket)
78 {
80 m_socket = nullptr;
81 }
82
83 m_socket = new MythSocket();
84
86 {
88 m_socket = nullptr;
89 }
90 else
91 {
92 m_zmclientReady = true;
93 m_bConnected = true;
94 }
95
96 usleep(999999);
97 }
98
99 if (!m_bConnected)
100 {
102 {
103 ShowNotificationError(tr("Can't connect to the mythzmserver") , "MythZoneMinder",
104 tr("Is it running? "
105 "Have you set the correct IP and port in the settings?"));
106 }
107 }
108
109 // check the server uses the same protocol as us
111 {
112 m_zmclientReady = false;
113 m_bConnected = false;
114 }
115
116 if (m_bConnected)
118
119 return m_bConnected;
120}
121
122bool ZMClient::sendReceiveStringList(QStringList &strList)
123{
124 QStringList origStrList = strList;
125
126 bool ok = false;
127 if (m_bConnected)
128 ok = m_socket->SendReceiveStringList(strList);
129
130 if (!ok)
131 {
132 LOG(VB_GENERAL, LOG_NOTICE, "Connection to mythzmserver lost");
133
135 {
136 LOG(VB_GENERAL, LOG_ERR, "Re-connection to mythzmserver failed");
137 return false;
138 }
139
140 // try to resend
141 strList = origStrList;
142 ok = m_socket->SendReceiveStringList(strList);
143 if (!ok)
144 {
145 m_bConnected = false;
146 return false;
147 }
148 }
149
150 // sanity check
151 if (strList.empty())
152 {
153 LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
154 return false;
155 }
156
157 // the server sends "UNKNOWN_COMMAND" if it did not recognise the command
158 if (strList[0] == "UNKNOWN_COMMAND")
159 {
160 LOG(VB_GENERAL, LOG_ERR, "Somethings is getting passed to the server "
161 "that it doesn't understand");
162 return false;
163 }
164
165 // the server sends "ERROR" if it failed to process the command
166 if (strList[0].startsWith("ERROR"))
167 {
168 LOG(VB_GENERAL, LOG_ERR,
169 QString("The server failed to process the command. "
170 "The error was:- \n\t\t\t%1").arg(strList[0]));
171 return false;
172 }
173
174 // we should get "OK" from the server if everything is OK
175 return strList[0] == "OK";
176}
177
179{
180 QMutexLocker locker(&m_commandLock);
181
182 QStringList strList("HELLO");
183 if (!sendReceiveStringList(strList))
184 {
185 LOG(VB_GENERAL, LOG_ERR, QString("Server didn't respond to 'HELLO'!!"));
186
187 ShowOkPopup(tr("The mythzmserver didn't respond to our request "
188 "to get the protocol version!!"));
189 return false;
190 }
191
192 // sanity check
193 if (strList.size() < 2)
194 {
195 LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
196 return false;
197 }
198
199 if (strList[1] != ZM_PROTOCOL_VERSION)
200 {
201 LOG(VB_GENERAL, LOG_ERR,
202 QString("Protocol version mismatch (plugin=%1, mythzmserver=%2)")
203 .arg(ZM_PROTOCOL_VERSION, strList[1]));
204
205 ShowOkPopup(QString("The mythzmserver uses protocol version %1, "
206 "but this client only understands version %2. "
207 "Make sure you are running compatible versions of "
208 "both the server and plugin.")
209 .arg(strList[1], ZM_PROTOCOL_VERSION));
210 return false;
211 }
212
213 LOG(VB_GENERAL, LOG_INFO,
214 QString("Using protocol version %1").arg(ZM_PROTOCOL_VERSION));
215 return true;
216}
217
219{
220 // Reset the flag
221 m_zmclientReady = false;
222 m_bConnected = false;
223
224 // Retry to connect. . . Maybe the user restarted mythzmserver?
226}
227
229{
230 QMutexLocker locker(&m_socketLock);
231
232 if (m_socket)
234
235 m_zmclientReady = false;
236 m_bConnected = false;
237}
238
240{
242
243 m_zmclient = nullptr;
244
245 if (m_socket)
246 {
247 m_socket->DecrRef();
248 m_socket = nullptr;
249 m_zmclientReady = false;
250 }
251
252 delete m_retryTimer;
253}
254
255void ZMClient::getServerStatus(QString &status, QString &cpuStat, QString &diskStat)
256{
257 QMutexLocker locker(&m_commandLock);
258
259 QStringList strList("GET_SERVER_STATUS");
260 if (!sendReceiveStringList(strList))
261 return;
262
263 // sanity check
264 if (strList.size() < 4)
265 {
266 LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
267 return;
268 }
269
270 status = strList[1];
271 cpuStat = strList[2];
272 diskStat = strList[3];
273}
274
276{
277 QMutexLocker clocker(&m_commandLock);
278
279 QStringList strList("GET_MONITOR_STATUS");
280 if (!sendReceiveStringList(strList))
281 return;
282
283 // sanity check
284 if (strList.size() < 2)
285 {
286 LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
287 return;
288 }
289
290 bool bOK = false;
291 int monitorCount = strList[1].toInt(&bOK);
292 if (!bOK)
293 {
294 LOG(VB_GENERAL, LOG_ERR,
295 "ZMClient received bad int in getMonitorStatus()");
296 return;
297 }
298
299 QMutexLocker locker(&m_listLock);
300
301 for (int x = 0; x < monitorCount; x++)
302 {
303 int monID = strList[(x * 7) + 2].toInt();
304
305 if (m_monitorMap.contains(monID))
306 {
307 Monitor *mon = m_monitorMap.find(monID).value();
308 mon->name = strList[(x * 7) + 3];
309 mon->zmcStatus = strList[(x * 7) + 4];
310 mon->zmaStatus = strList[(x * 7) + 5];
311 mon->events = strList[(x * 7) + 6].toInt();
312 mon->function = strList[(x * 7) + 7];
313 mon->enabled = (strList[(x * 7) + 8].toInt() != 0);
314 }
315 }
316}
317
318static QString stateToString(State state)
319{
320 QString result = "UNKNOWN";
321
322 switch (state)
323 {
324 case IDLE:
325 result = "IDLE";
326 break;
327 case PREALARM:
328 result = "PREALARM";
329 break;
330 case ALARM:
331 result = "ALARM";
332 break;
333 case ALERT:
334 result = "ALERT";
335 break;
336 case TAPE:
337 result = "TAPE";
338 break;
339 default:
340 result = "UNKNOWN";
341 }
342
343 return result;
344}
345
347{
348 QMutexLocker clocker(&m_commandLock);
349
350 QStringList strList("GET_ALARM_STATES");
351 if (!sendReceiveStringList(strList))
352 return false;
353
354 // sanity check
355 if (strList.size() < 2)
356 {
357 LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
358 return false;
359 }
360
361 bool bOK = false;
362 int monitorCount = strList[1].toInt(&bOK);
363 if (!bOK)
364 {
365 LOG(VB_GENERAL, LOG_ERR,
366 "ZMClient received bad int in getAlarmStates()");
367 return false;
368 }
369
370 QMutexLocker locker(&m_listLock);
371
372 bool changed = false;
373 for (int x = 0; x < monitorCount; x++)
374 {
375 int monID = strList[(x * 2) + 2].toInt();
376 auto state = (State)strList[(x * 2) + 3].toInt();
377
378 if (m_monitorMap.contains(monID))
379 {
380 Monitor *mon = m_monitorMap.find(monID).value();
381 if (mon->state != state)
382 {
383 // alarm state has changed for this monitor
384 LOG(VB_GENERAL, LOG_DEBUG,
385 QString("ZMClient monitor %1 changed state from %2 to %3")
386 .arg(mon->name, stateToString(mon->state), stateToString(state)));
387 mon->previousState = mon->state;
388 mon->state = state;
389 changed = true;
390 }
391 }
392 }
393
394 return changed;
395}
396
397void ZMClient::getEventList(const QString &monitorName, bool oldestFirst,
398 const QString &date, bool includeContinuous,
399 std::vector<Event*> *eventList)
400{
401 QMutexLocker locker(&m_commandLock);
402
403 eventList->clear();
404
405 QStringList strList("GET_EVENT_LIST");
406 strList << monitorName << (oldestFirst ? "1" : "0") ;
407 strList << date;
408 strList << (includeContinuous ? "1" : "0") ;
409
410 if (!sendReceiveStringList(strList))
411 return;
412
413 // sanity check
414 if (strList.size() < 2)
415 {
416 LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
417 return;
418 }
419
420 bool bOK = false;
421 int eventCount = strList[1].toInt(&bOK);
422 if (!bOK)
423 {
424 LOG(VB_GENERAL, LOG_ERR, "ZMClient received bad int in getEventList()");
425 return;
426 }
427
428 // sanity check
429 if ((strList.size() - 2) / 6 != eventCount)
430 {
431 LOG(VB_GENERAL, LOG_ERR,
432 "ZMClient got a mismatch between the number of events and "
433 "the expected number of stringlist items in getEventList()");
434 return;
435 }
436
437 QStringList::Iterator it = strList.begin();
438 it++; it++;
439 for (int x = 0; x < eventCount; x++)
440 {
441 eventList->push_back(
442 new Event(
443 (*it++).toInt(), /* eventID */
444 *it++, /* eventName */
445 (*it++).toInt(), /* monitorID */
446 *it++, /* monitorName */
447 QDateTime::fromString(*it++, Qt::ISODate), /* startTime */
448 *it++ /* length */));
449 }
450}
451
452void ZMClient::getEventDates(const QString &monitorName, bool oldestFirst,
453 QStringList &dateList)
454{
455 QMutexLocker locker(&m_commandLock);
456
457 dateList.clear();
458
459 QStringList strList("GET_EVENT_DATES");
460 strList << monitorName << (oldestFirst ? "1" : "0") ;
461
462 if (!sendReceiveStringList(strList))
463 return;
464
465 // sanity check
466 if (strList.size() < 2)
467 {
468 LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
469 return;
470 }
471
472 bool bOK = false;
473 int dateCount = strList[1].toInt(&bOK);
474 if (!bOK)
475 {
476 LOG(VB_GENERAL, LOG_ERR,
477 "ZMClient received bad int in getEventDates()");
478 return;
479 }
480
481 // sanity check
482 if ((strList.size() - 3) != dateCount)
483 {
484 LOG(VB_GENERAL, LOG_ERR,
485 "ZMClient got a mismatch between the number of dates and "
486 "the expected number of stringlist items in getEventDates()");
487 return;
488 }
489
490 QStringList::Iterator it = strList.begin();
491 it++; it++;
492 for (int x = 0; x < dateCount; x++)
493 {
494 dateList.append(*it++);
495 }
496}
497
498void ZMClient::getFrameList(int eventID, std::vector<Frame*> *frameList)
499{
500 QMutexLocker locker(&m_commandLock);
501
502 frameList->clear();
503
504 QStringList strList("GET_FRAME_LIST");
505 strList << QString::number(eventID);
506 if (!sendReceiveStringList(strList))
507 return;
508
509 // sanity check
510 if (strList.size() < 2)
511 {
512 LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
513 return;
514 }
515
516 bool bOK = false;
517 int frameCount = strList[1].toInt(&bOK);
518 if (!bOK)
519 {
520 LOG(VB_GENERAL, LOG_ERR, "ZMClient received bad int in getFrameList()");
521 return;
522 }
523
524 // sanity check
525 if ((strList.size() - 2) / 2 != frameCount)
526 {
527 LOG(VB_GENERAL, LOG_ERR,
528 "ZMClient got a mismatch between the number of frames and "
529 "the expected number of stringlist items in getFrameList()");
530 return;
531 }
532
533 QStringList::Iterator it = strList.begin();
534 it++; it++;
535 for (int x = 0; x < frameCount; x++)
536 {
537 auto *item = new Frame;
538 item->type = *it++;
539 item->delta = (*it++).toDouble();
540 frameList->push_back(item);
541 }
542}
543
544void ZMClient::deleteEvent(int eventID)
545{
546 QMutexLocker locker(&m_commandLock);
547
548 QStringList strList("DELETE_EVENT");
549 strList << QString::number(eventID);
550 sendReceiveStringList(strList);
551}
552
553void ZMClient::deleteEventList(std::vector<Event*> *eventList)
554{
555 QMutexLocker locker(&m_commandLock);
556
557 // delete events in 100 event chunks
558 QStringList strList("DELETE_EVENT_LIST");
559 int count = 0;
560 std::vector<Event*>::iterator it;
561 for (it = eventList->begin(); it != eventList->end(); ++it)
562 {
563 strList << QString::number((*it)->eventID());
564
565 if (++count == 100)
566 {
567 sendReceiveStringList(strList);
568 strList = QStringList("DELETE_EVENT_LIST");
569 count = 0;
570 }
571 }
572
573 // make sure the last chunk is deleted
574 sendReceiveStringList(strList);
575
576 // run zmaudit to clean up the orphaned db entries
577 strList = QStringList("RUN_ZMAUDIT");
578 sendReceiveStringList(strList);
579}
580
581bool ZMClient::readData(unsigned char *data, int dataSize)
582{
583 qint64 read = 0;
584 std::chrono::milliseconds errmsgtime { 0ms };
585 MythTimer timer;
586 timer.start();
587
588 while (dataSize > 0)
589 {
590 qint64 sret = m_socket->Read((char*) data + read, dataSize, 100ms);
591 if (sret > 0)
592 {
593 read += sret;
594 dataSize -= sret;
595 if (dataSize > 0)
596 {
597 timer.start();
598 }
599 }
600 else if (sret < 0)
601 {
602 LOG(VB_GENERAL, LOG_ERR, "readData: Error, readBlock");
604 return false;
605 }
606 else if (!m_socket->IsConnected())
607 {
608 LOG(VB_GENERAL, LOG_ERR,
609 "readData: Error, socket went unconnected");
611 return false;
612 }
613 else
614 {
615 std::chrono::milliseconds elapsed = timer.elapsed();
616 if (elapsed > 10s)
617 {
618 if ((elapsed - errmsgtime) > 10s)
619 {
620 errmsgtime = elapsed;
621 LOG(VB_GENERAL, LOG_ERR,
622 QString("m_socket->: Waiting for data: %1 %2")
623 .arg(read).arg(dataSize));
624 }
625 }
626
627 if (elapsed > 100s)
628 {
629 LOG(VB_GENERAL, LOG_ERR, "Error, readData timeout (readBlock)");
630 return false;
631 }
632 }
633 }
634
635 return true;
636}
637
638void ZMClient::getEventFrame(Event *event, int frameNo, MythImage **image)
639{
640 QMutexLocker locker(&m_commandLock);
641
642 if (*image)
643 {
644 (*image)->DecrRef();
645 *image = nullptr;
646 }
647
648 QStringList strList("GET_EVENT_FRAME");
649 strList << QString::number(event->monitorID());
650 strList << QString::number(event->eventID());
651 strList << QString::number(frameNo);
652#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
653 strList << event->startTime(Qt::LocalTime).toString("yy/MM/dd/hh/mm/ss");
654#else
655 static const QTimeZone localtime(QTimeZone::LocalTime);
656 strList << event->startTime(localtime).toString("yy/MM/dd/hh/mm/ss");
657#endif
658 if (!sendReceiveStringList(strList))
659 return;
660
661 // sanity check
662 if (strList.size() < 2)
663 {
664 LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
665 return;
666 }
667
668 // get frame length from data
669 int imageSize = strList[1].toInt();
670
671 // grab the image data
672 auto *data = new unsigned char[imageSize];
673 if (!readData(data, imageSize))
674 {
675 LOG(VB_GENERAL, LOG_ERR,
676 "ZMClient::getEventFrame(): Failed to get image data");
677 delete [] data;
678 return;
679 }
680
681 // get a MythImage
683
684 // extract the image data and create a MythImage from it
685 if (!(*image)->loadFromData(data, imageSize, "JPEG"))
686 {
687 LOG(VB_GENERAL, LOG_ERR,
688 "ZMClient::getEventFrame(): Failed to load image from data");
689 }
690
691 delete [] data;
692}
693
694void ZMClient::getAnalyseFrame(Event *event, int frameNo, QImage &image)
695{
696 QMutexLocker locker(&m_commandLock);
697
698 QStringList strList("GET_ANALYSE_FRAME");
699 strList << QString::number(event->monitorID());
700 strList << QString::number(event->eventID());
701 strList << QString::number(frameNo);
702#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
703 strList << event->startTime(Qt::LocalTime).toString("yy/MM/dd/hh/mm/ss");
704#else
705 static const QTimeZone localtime(QTimeZone::LocalTime);
706 strList << event->startTime(localtime).toString("yy/MM/dd/hh/mm/ss");
707#endif
708 if (!sendReceiveStringList(strList))
709 {
710 image = QImage();
711 return;
712 }
713
714 // sanity check
715 if (strList.size() < 2)
716 {
717 LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
718 return;
719 }
720
721 // get frame length from data
722 int imageSize = strList[1].toInt();
723
724 // grab the image data
725 auto *data = new unsigned char[imageSize];
726 if (!readData(data, imageSize))
727 {
728 LOG(VB_GENERAL, LOG_ERR,
729 "ZMClient::getAnalyseFrame(): Failed to get image data");
730 image = QImage();
731 }
732 else
733 {
734 // extract the image data and create a QImage from it
735 if (!image.loadFromData(data, imageSize, "JPEG"))
736 {
737 LOG(VB_GENERAL, LOG_ERR,
738 "ZMClient::getAnalyseFrame(): Failed to load image from data");
739 image = QImage();
740 }
741 }
742
743 delete [] data;
744}
745
746int ZMClient::getLiveFrame(int monitorID, QString &status, FrameData& buffer)
747{
748 QMutexLocker locker(&m_commandLock);
749
750 QStringList strList("GET_LIVE_FRAME");
751 strList << QString::number(monitorID);
752 if (!sendReceiveStringList(strList))
753 {
754 if (strList.empty())
755 {
756 LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
757 return 0;
758 }
759
760 // the server sends a "WARNING" message if there is no new
761 // frame available we can safely ignore it
762 if (strList[0].startsWith("WARNING"))
763 {
764 return 0;
765 }
766 status = strList[0];
767 return 0;
768 }
769
770 // sanity check
771 if (strList.size() < 4)
772 {
773 LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
774 return 0;
775 }
776
777 // get status
778 status = strList[2];
779
780 // get frame length from data
781 size_t imageSize = strList[3].toInt();
782
783 if (buffer.size() < imageSize)
784 {
785 LOG(VB_GENERAL, LOG_ERR,
786 "ZMClient::getLiveFrame(): Live frame buffer is too small!");
787 return 0;
788 }
789
790 // read the frame data
791 if (imageSize == 0)
792 return 0;
793
794 if (!readData(buffer.data(), imageSize))
795 {
796 LOG(VB_GENERAL, LOG_ERR,
797 "ZMClient::getLiveFrame(): Failed to get image data");
798 return 0;
799 }
800
801 return imageSize;
802}
803
804void ZMClient::getCameraList(QStringList &cameraList)
805{
806 QMutexLocker locker(&m_commandLock);
807
808 cameraList.clear();
809
810 QStringList strList("GET_CAMERA_LIST");
811 if (!sendReceiveStringList(strList))
812 return;
813
814 // sanity check
815 if (strList.size() < 2)
816 {
817 LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
818 return;
819 }
820
821 bool bOK = false;
822 int cameraCount = strList[1].toInt(&bOK);
823 if (!bOK)
824 {
825 LOG(VB_GENERAL, LOG_ERR,
826 "ZMClient received bad int in getCameraList()");
827 return;
828 }
829
830 // sanity check
831 if (strList.size() < cameraCount + 2)
832 {
833 LOG(VB_GENERAL, LOG_ERR, QString(
834 "ZMClient got a mismatch between the number of cameras (%1) and "
835 "the expected number of stringlist items (%2) in getCameraList()")
836 .arg(cameraCount).arg(strList.size()));
837 return;
838 }
839
840 for (int x = 0; x < cameraCount; x++)
841 {
842 cameraList.append(strList[x + 2]);
843 }
844}
845
847{
848 QMutexLocker locker(&m_listLock);
849 return m_monitorList.count();
850}
851
853{
854 QMutexLocker locker(&m_listLock);
855
856 if (pos < 0 || pos > m_monitorList.count() - 1)
857 return nullptr;
858
859 return m_monitorList.at(pos);
860}
861
863{
864 QMutexLocker locker(&m_listLock);
865
866 if (m_monitorMap.contains(monID))
867 return m_monitorMap.find(monID).value();
868
869 return nullptr;
870}
871
873{
874 QMutexLocker clocker(&m_commandLock);
875 QMutexLocker locker(&m_listLock);
876
877 for (int x = 0; x < m_monitorList.count(); x++)
878 delete m_monitorList.at(x);
879
880 m_monitorList.clear();
881 m_monitorMap.clear();
882
883 QStringList strList("GET_MONITOR_LIST");
884 if (!sendReceiveStringList(strList))
885 return;
886
887 // sanity check
888 if (strList.size() < 2)
889 {
890 LOG(VB_GENERAL, LOG_ERR, "ZMClient response too short");
891 return;
892 }
893
894 bool bOK = false;
895 int monitorCount = strList[1].toInt(&bOK);
896 if (!bOK)
897 {
898 LOG(VB_GENERAL, LOG_ERR,
899 "ZMClient received bad int in getMonitorList()");
900 return;
901 }
902
903 // sanity check
904 if ((strList.size() - 2) / 5 != monitorCount)
905 {
906 LOG(VB_GENERAL, LOG_ERR,
907 "ZMClient got a mismatch between the number of monitors and "
908 "the expected number of stringlist items in getMonitorList()");
909 return;
910 }
911
912 // get list of monitor id's that need monitoring
913 QString s = gCoreContext->GetSetting("ZoneMinderNotificationMonitors");
914 QStringList notificationMonitors = s.split(",");
915
916 for (int x = 0; x < monitorCount; x++)
917 {
918 auto *item = new Monitor;
919 item->id = strList[(x * 5) + 2].toInt();
920 item->name = strList[(x * 5) + 3];
921 item->width = strList[(x * 5) + 4].toInt();
922 item->height = strList[(x * 5) + 5].toInt();
923 item->bytes_per_pixel = strList[(x * 5) + 6].toInt();
924 item->zmcStatus = "";
925 item->zmaStatus = "";
926 item->events = 0;
927 item->status = "";
928 item->showNotifications = notificationMonitors.contains(QString::number(item->id));
929
930 m_monitorList.append(item);
931 m_monitorMap.insert(item->id, item);
932
933 LOG(VB_GENERAL, LOG_NOTICE,
934 QString("Monitor: %1 (%2) is using %3 bytes per pixel")
935 .arg(item->name).arg(item->id).arg(item->bytes_per_pixel));
936 }
937}
938
939void ZMClient::setMonitorFunction(const int monitorID, const QString &function, const bool enabled)
940{
941 QMutexLocker locker(&m_commandLock);
942
943 QStringList strList("SET_MONITOR_FUNCTION");
944 strList << QString::number(monitorID);
945 strList << function;
946 strList << QString::number(static_cast<int>(enabled));
947
948 if (!sendReceiveStringList(strList))
949 return;
950}
951
953{
954 QString s;
955
956 for (int x = 0; x < m_monitorList.count(); x++)
957 {
958 Monitor *mon = m_monitorList.at(x);
959 if (mon->showNotifications)
960 {
961 if (!s.isEmpty())
962 s += QString(",%1").arg(mon->id);
963 else
964 s = QString("%1").arg(mon->id);
965 }
966 }
967
968 gCoreContext->SaveSetting("ZoneMinderNotificationMonitors", s);
969}
970
971void ZMClient::customEvent (QEvent* event)
972{
973 if (event->type() == MythEvent::kMythEventMessage)
974 {
975 auto *me = dynamic_cast<MythEvent*>(event);
976 if (!me)
977 return;
978
979 if (me->Message().startsWith("ZONEMINDER_NOTIFICATION"))
980 {
981 QStringList list = me->Message().simplified().split(' ');
982
983 if (list.size() < 2)
984 return;
985
986 int monID = list[1].toInt();
987 showMiniPlayer(monID);
988 }
989 }
990
991 QObject::customEvent(event);
992}
993
994void ZMClient::showMiniPlayer(int monitorID) const
995{
996 if (!isMiniPlayerEnabled())
997 return;
998
999 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1000
1001 auto *miniPlayer = new ZMMiniPlayer(popupStack);
1002
1003 miniPlayer->setAlarmMonitor(monitorID);
1004
1005 if (miniPlayer->Create())
1006 popupStack->AddScreen(miniPlayer);
1007}
Event details.
Definition: zmdefines.h:28
int eventID(void) const
Definition: zmdefines.h:49
int monitorID(void) const
Definition: zmdefines.h:47
State state
Definition: zmdefines.h:131
int events
Definition: zmdefines.h:123
QString function
Definition: zmdefines.h:118
int id
Definition: zmdefines.h:115
QString zmaStatus
Definition: zmdefines.h:122
bool enabled
Definition: zmdefines.h:119
bool showNotifications
Definition: zmdefines.h:130
QString name
Definition: zmdefines.h:116
State previousState
Definition: zmdefines.h:132
QString zmcStatus
Definition: zmdefines.h:121
void SaveSetting(const QString &key, int newValue)
QString GetSetting(const QString &key, const QString &defaultval="")
int GetNumSetting(const QString &key, int defaultval=0)
This class is used as a container for messages.
Definition: mythevent.h:17
const QString & Message() const
Definition: mythevent.h:65
static const Type kMythEventMessage
Definition: mythevent.h:79
MythPainter * GetPainter()
MythScreenStack * GetStack(const QString &Stackname)
void addListener(QObject *listener)
Add a listener to the observable.
void removeListener(QObject *listener)
Remove a listener to the observable.
MythImage * GetFormatImage()
Returns a blank reference counted image in the format required for the Draw functions for this painte...
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Class for communcating between myth backends and frontends.
Definition: mythsocket.h:26
bool SendReceiveStringList(QStringList &list, uint min_reply_length=0, std::chrono::milliseconds timeoutMS=kLongTimeout)
Definition: mythsocket.cpp:326
bool IsConnected(void) const
Definition: mythsocket.cpp:551
int Read(char *data, int size, std::chrono::milliseconds max_wait)
Definition: mythsocket.cpp:527
void DisconnectFromHost(void)
Definition: mythsocket.cpp:498
bool ConnectToHost(const QString &hostname, quint16 port)
connect to host
Definition: mythsocket.cpp:374
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:14
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:91
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
void doGetMonitorList(void)
Definition: zmclient.cpp:872
QTimer * m_retryTimer
Definition: zmclient.h:91
int getMonitorCount(void)
Definition: zmclient.cpp:846
bool sendReceiveStringList(QStringList &strList)
Definition: zmclient.cpp:122
bool isMiniPlayerEnabled(void) const
Definition: zmclient.h:67
void getEventFrame(Event *event, int frameNo, MythImage **image)
Definition: zmclient.cpp:638
QMap< int, Monitor * > m_monitorMap
Definition: zmclient.h:84
void deleteEventList(std::vector< Event * > *eventList)
Definition: zmclient.cpp:553
void updateMonitorStatus(void)
Definition: zmclient.cpp:275
void shutdown()
Definition: zmclient.cpp:228
uint m_port
Definition: zmclient.h:89
ZMClient()
Definition: zmclient.cpp:25
QRecursiveMutex m_listLock
Definition: zmclient.h:81
void getAnalyseFrame(Event *event, int frameNo, QImage &image)
Definition: zmclient.cpp:694
Monitor * getMonitorByID(int monID)
Definition: zmclient.cpp:862
bool readData(unsigned char *data, int dataSize)
Definition: zmclient.cpp:581
void deleteEvent(int eventID)
Definition: zmclient.cpp:544
void customEvent(QEvent *event) override
Definition: zmclient.cpp:971
QList< Monitor * > m_monitorList
Definition: zmclient.h:83
Monitor * getMonitorAt(int pos)
Definition: zmclient.cpp:852
bool m_bConnected
Definition: zmclient.h:90
void getServerStatus(QString &status, QString &cpuStat, QString &diskStat)
Definition: zmclient.cpp:255
MythSocket * m_socket
Definition: zmclient.h:86
static ZMClient * get(void)
Definition: zmclient.cpp:37
bool updateAlarmStates(void)
Definition: zmclient.cpp:346
void getEventDates(const QString &monitorName, bool oldestFirst, QStringList &dateList)
Definition: zmclient.cpp:452
void getCameraList(QStringList &cameraList)
Definition: zmclient.cpp:804
void saveNotificationMonitors(void)
Definition: zmclient.cpp:952
void getEventList(const QString &monitorName, bool oldestFirst, const QString &date, bool includeContinuous, std::vector< Event * > *eventList)
Definition: zmclient.cpp:397
static bool setupZMClient(void)
Definition: zmclient.cpp:44
void setMonitorFunction(int monitorID, const QString &function, bool enabled)
Definition: zmclient.cpp:939
void getFrameList(int eventID, std::vector< Frame * > *frameList)
Definition: zmclient.cpp:498
bool connectToHost(const QString &hostname, unsigned int port)
Definition: zmclient.cpp:61
QRecursiveMutex m_commandLock
Definition: zmclient.h:82
QRecursiveMutex m_socketLock
Definition: zmclient.h:87
bool checkProtoVersion(void)
Definition: zmclient.cpp:178
static ZMClient * m_zmclient
Definition: zmclient.h:26
QString m_hostname
Definition: zmclient.h:88
bool m_zmclientReady
Definition: zmclient.h:92
void restartConnection(void)
Definition: zmclient.cpp:218
~ZMClient() override
Definition: zmclient.cpp:239
int getLiveFrame(int monitorID, QString &status, FrameData &buffer)
Definition: zmclient.cpp:746
void showMiniPlayer(int monitorID) const
Definition: zmclient.cpp:994
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythNotificationCenter * GetNotificationCenter(void)
MythMainWindow * GetMythMainWindow(void)
void ShowNotificationError(const QString &msg, const QString &from, const QString &detail, const VNMask visibility, const MythNotification::Priority priority)
convenience utility to display error message as notification
@ ISODate
Default UTC.
Definition: mythdate.h:17
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:39
def read(device=None, features=[])
Definition: disc.py:35
QString type
Definition: zmdefines.h:104
static QString stateToString(State state)
Definition: zmclient.cpp:318
static constexpr const char * ZM_PROTOCOL_VERSION
Definition: zmclient.cpp:23
State
Definition: zmserver.h:69
@ TAPE
Definition: zmserver.h:74
@ ALERT
Definition: zmserver.h:73
@ ALARM
Definition: zmserver.h:72
@ PREALARM
Definition: zmserver.h:71
@ IDLE
Definition: zmserver.h:70
std::array< uint8_t, MAX_IMAGE_SIZE > FrameData
Definition: zmserver.h:33