Skip to content

Commit c642f3e

Browse files
committed
2 parents 116d62a + 8a49c8f commit c642f3e

File tree

10 files changed

+175
-21
lines changed

10 files changed

+175
-21
lines changed

History.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Version 2.3xxx
3030
- Implemented: Waterflow sensor
3131
- Implemented: Wind Beaufort scale
3232
- Implemented: Wind Graph, option to delete a short-log data point
33+
- Implemented: Panasonic TV support (Viera TV's after 2011 should work)
3334
- Changed: Alert sensor, removed level notation in user interface
3435
- Changed: EventSystem, don't process unused devices
3536
- Changed: Fritzbox, Now updating text sensor on connect/disconnect

hardware/PanasonicTV.cpp

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,14 @@ CPanasonicNode::~CPanasonicNode(void)
164164
if (DEBUG_LOGGING) _log.Log(LOG_STATUS, "Panasonic Plugin: (%s) Destroyed.", m_Name.c_str());
165165
}
166166

167-
void CPanasonicNode::UpdateStatus()
167+
void CPanasonicNode::UpdateStatus(bool forceupdate)
168168
{
169169
std::vector<std::vector<std::string> > result;
170170
m_CurrentStatus.LastOK(mytime(NULL));
171171

172172
// 1: Update the DeviceStatus
173173

174-
if (m_CurrentStatus.UpdateRequired(m_PreviousStatus))
174+
if (m_CurrentStatus.UpdateRequired(m_PreviousStatus) || forceupdate)
175175
{
176176
result = m_sql.safe_query("UPDATE DeviceStatus SET nValue=%d, sValue='%q', LastUpdate='%q' WHERE (HardwareID == %d) AND (DeviceID == '%q') AND (Unit == 1) AND (SwitchType == %d)",
177177
int(m_CurrentStatus.Status()), m_CurrentStatus.StatusMessage().c_str(), m_CurrentStatus.LastOK().c_str(), m_HwdID, m_szDevID, STYPE_Media);
@@ -180,15 +180,15 @@ void CPanasonicNode::UpdateStatus()
180180
// 2: Log the event if the actual status has changed
181181
std::string sLogText = m_CurrentStatus.StatusText();
182182

183-
if (m_CurrentStatus.LogRequired(m_PreviousStatus))
183+
if (m_CurrentStatus.LogRequired(m_PreviousStatus) || forceupdate)
184184
{
185185
if (m_CurrentStatus.IsOn()) sLogText += " - " + m_CurrentStatus.LogMessage();
186186
result = m_sql.safe_query("INSERT INTO LightingLog (DeviceRowID, nValue, sValue) VALUES (%d, %d, '%q')", m_ID, int(m_CurrentStatus.Status()), sLogText.c_str());
187187
_log.Log(LOG_NORM, "Panasonic: (%s) Event: '%s'.", m_Name.c_str(), sLogText.c_str());
188188
}
189189

190190
// 3: Trigger On/Off actions
191-
if (m_CurrentStatus.OnOffRequired(m_PreviousStatus))
191+
if (m_CurrentStatus.OnOffRequired(m_PreviousStatus) || forceupdate)
192192
{
193193
result = m_sql.safe_query("SELECT StrParam1,StrParam2 FROM DeviceStatus WHERE (HardwareID==%d) AND (ID = '%q') AND (Unit == 1)", m_HwdID, m_szDevID);
194194
if (result.size() > 0)
@@ -199,7 +199,7 @@ void CPanasonicNode::UpdateStatus()
199199

200200
// 4: Trigger Notifications & events on status change
201201

202-
if (m_CurrentStatus.Status() != m_PreviousStatus.Status())
202+
if (m_CurrentStatus.Status() != m_PreviousStatus.Status() || forceupdate)
203203
{
204204
m_notifications.CheckAndHandleNotification(m_ID, m_Name, m_CurrentStatus.NotificationType(), sLogText);
205205
m_mainworker.m_eventsystem.ProcessDevice(m_HwdID, m_ID, 1, int(pTypeLighting2), int(sTypeAC), 12, 100, int(m_CurrentStatus.Status()), m_CurrentStatus.StatusMessage().c_str(), m_Name.c_str(), 0);
@@ -215,11 +215,10 @@ bool CPanasonicNode::handleConnect(boost::asio::ip::tcp::socket& socket, boost::
215215
if (!m_stoprequested)
216216
{
217217
socket.connect(endpoint, ec);
218-
219218
if (!ec)
220219
{
221220
if (DEBUG_LOGGING) _log.Log(LOG_NORM, "Panasonic Plugin: (%s) Connected to '%s:%s'.", m_Name.c_str(), m_IP.c_str(), (m_Port[0] != '-' ? m_Port.c_str() : m_Port.substr(1).c_str()));
222-
if (m_CurrentStatus.Status() == MSTAT_OFF)
221+
if (m_CurrentStatus.Status() != MSTAT_ON)
223222
{
224223
m_CurrentStatus.Clear();
225224
m_CurrentStatus.Status(MSTAT_ON);
@@ -250,6 +249,7 @@ bool CPanasonicNode::handleConnect(boost::asio::ip::tcp::socket& socket, boost::
250249

251250
}
252251

252+
253253
std::string CPanasonicNode::handleWriteAndRead(std::string pMessageToSend)
254254
{
255255

@@ -451,9 +451,16 @@ void CPanasonicNode::Do_Work()
451451

452452
void CPanasonicNode::SendCommand(const std::string command)
453453
{
454-
std::string sPanasonicCall;
455-
std::string sPanasonicParam = "";
454+
std::string sPanasonicCall = "";
456455

456+
if (m_CurrentStatus.Status() == MSTAT_OFF)
457+
{
458+
// no point trying to send a command if we know the device is off
459+
// no network on Panasonic TV's when it's in the off state
460+
_log.Log(LOG_ERROR, "Panasonic Plugin: (%s) Device is Off, cannot send command.", m_Name.c_str());
461+
return;
462+
}
463+
457464
if (command == "Home")
458465
sPanasonicCall = buildXMLStringNetCtl("CANCEL-ONOFF");
459466
else if (command == "Up")
@@ -490,7 +497,7 @@ void CPanasonicNode::SendCommand(const std::string command)
490497
sPanasonicCall = buildXMLStringNetCtl("MENU-ONOFF");
491498
else if (command == "Channels" || command == "guide")
492499
sPanasonicCall = buildXMLStringNetCtl("EPG-ONOFF");
493-
else if (command == "Back" || command == "return")
500+
else if (command == "Back" || command == "Return")
494501
sPanasonicCall = buildXMLStringNetCtl("RETURN-ONOFF");
495502
else if (command == "Select")
496503
sPanasonicCall = buildXMLStringNetCtl("ENTER-ONOFF");
@@ -534,10 +541,18 @@ void CPanasonicNode::SendCommand(const std::string command)
534541
sPanasonicCall = buildXMLStringNetCtl("STOP-ONOFF");
535542
else if (command == "pause")
536543
sPanasonicCall = buildXMLStringNetCtl("PAUSE-ONOFF");
537-
else if (command == "Power" || command == "power" || command == "off")
544+
else if (command == "Power" || command == "power" || command == "off" || command == "Off")
538545
sPanasonicCall = buildXMLStringNetCtl("POWER-ONOFF");
539546
else if (command == "ShowSubtitles")
540547
sPanasonicCall = buildXMLStringNetCtl("STTL-ONOFF");
548+
else if (command == "On" || command == "on")
549+
{
550+
_log.Log(LOG_NORM, "Panasonic Plugin: (%s) Can't use command: '%s'.", m_Name.c_str(), command.c_str());
551+
// Workaround to get the plugin to reset device status, otherwise the UI goes out of sync with plugin
552+
m_CurrentStatus.Clear();
553+
m_CurrentStatus.Status(MSTAT_UNKNOWN);
554+
UpdateStatus(true);
555+
}
541556
else
542557
_log.Log(LOG_NORM, "Panasonic Plugin: (%s) Unknown command: '%s'.", m_Name.c_str(), command.c_str());
543558

@@ -721,6 +736,9 @@ bool CPanasonic::WriteToHardware(const char *pdata, const unsigned char length)
721736
int iParam = pSen->LIGHTING2.level;
722737
switch (pSen->LIGHTING2.cmnd)
723738
{
739+
case light2_sOn:
740+
(*itt)->SendCommand("On");
741+
return true;
724742
case light2_sOff:
725743
(*itt)->SendCommand("Off");
726744
return true;

hardware/PanasonicTV.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class CPanasonicNode //: public boost::enable_shared_from_this<CPanasonicNode>
5151
bool SendShutdown();
5252
void StopRequest() { m_stoprequested = true; };
5353
bool IsBusy() { return m_Busy; };
54-
bool IsOn() { return (m_CurrentStatus.Status() != MSTAT_OFF); };
54+
bool IsOn() { return (m_CurrentStatus.Status() == MSTAT_ON); };
5555

5656
int m_ID;
5757
int m_DevID;
@@ -69,15 +69,16 @@ class CPanasonicNode //: public boost::enable_shared_from_this<CPanasonicNode>
6969
std::string buildXMLStringRendCtl(std::string, std::string);
7070
std::string buildXMLStringRendCtl(std::string, std::string, std::string);
7171
std::string buildXMLStringNetCtl(std::string);
72-
72+
7373
int m_HwdID;
7474
char m_szDevID[40];
7575
std::string m_IP;
7676
std::string m_Port;
7777

7878
CPanasonicStatus m_PreviousStatus;
7979
CPanasonicStatus m_CurrentStatus;
80-
void UpdateStatus();
80+
//void UpdateStatus();
81+
void UpdateStatus(bool force = false);
8182

8283
std::string m_ExecuteCommand;
8384

main/SQLHelper.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2999,7 +2999,10 @@ unsigned long long CSQLHelper::UpdateValueInt(const int HardwareID, const char*
29992999
//Check for notifications
30003000
if (HWtype != HTYPE_LogitechMediaServer) // Skip notifications for LMS here; is handled by the LMS plug-in
30013001
{
3002-
m_notifications.CheckAndHandleSwitchNotification(ulID, devname, (bIsLightSwitchOn) ? NTYPE_SWITCH_ON : NTYPE_SWITCH_OFF);
3002+
if (switchtype == STYPE_Selector)
3003+
m_notifications.CheckAndHandleSwitchNotification(ulID, devname, (bIsLightSwitchOn) ? NTYPE_SWITCH_ON : NTYPE_SWITCH_OFF, llevel);
3004+
else
3005+
m_notifications.CheckAndHandleSwitchNotification(ulID, devname, (bIsLightSwitchOn) ? NTYPE_SWITCH_ON : NTYPE_SWITCH_OFF);
30033006
}
30043007
if (bIsLightSwitchOn)
30053008
{

main/WebServer.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5337,7 +5337,12 @@ namespace http {
53375337
(ntype == NTYPE_DEWPOINT)
53385338
)
53395339
{
5340-
strcpy(szTmp, ttype.c_str());
5340+
if ((ntype == NTYPE_SWITCH_ON) && (swhen == "2")) { // '='
5341+
unsigned char twhen = '=';
5342+
sprintf(szTmp, "%s;%c;%s", ttype.c_str(), twhen, svalue.c_str());
5343+
}
5344+
else
5345+
strcpy(szTmp, ttype.c_str());
53415346
}
53425347
else
53435348
{
@@ -5385,7 +5390,12 @@ namespace http {
53855390
(ntype == NTYPE_DEWPOINT)
53865391
)
53875392
{
5388-
strcpy(szTmp, ttype.c_str());
5393+
if ((ntype == NTYPE_SWITCH_ON) && (swhen == "2")) { // '='
5394+
unsigned char twhen = '=';
5395+
sprintf(szTmp, "%s;%c;%s", ttype.c_str(), twhen, svalue.c_str());
5396+
}
5397+
else
5398+
strcpy(szTmp, ttype.c_str());
53895399
}
53905400
else
53915401
{

notifications/NotificationHelper.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "NotificationHTTP.h"
1616
#include "NotificationKodi.h"
1717
#include "NotificationLogitechMediaServer.h"
18+
#include <boost/lexical_cast.hpp>
1819
#include <map>
1920

2021
#if defined WIN32
@@ -664,6 +665,94 @@ bool CNotificationHelper::CheckAndHandleSwitchNotification(
664665
return true;
665666
}
666667

668+
bool CNotificationHelper::CheckAndHandleSwitchNotification(
669+
const unsigned long long Idx,
670+
const std::string &devicename,
671+
const _eNotificationTypes ntype,
672+
const int llevel)
673+
{
674+
std::vector<_tNotification> notifications = GetNotifications(Idx);
675+
if (notifications.size() == 0)
676+
return false;
677+
std::vector<std::vector<std::string> > result;
678+
679+
result = m_sql.safe_query("SELECT SwitchType, CustomImage, Options FROM DeviceStatus WHERE (ID=%llu)",
680+
Idx);
681+
if (result.size() == 0)
682+
return false;
683+
_eSwitchType switchtype = (_eSwitchType)atoi(result[0][0].c_str());
684+
std::string szExtraData = "|Name=" + devicename + "|SwitchType=" + result[0][0] + "|CustomImage=" + result[0][1] + "|";
685+
std::string sOptions = result[0][2].c_str();
686+
687+
std::string msg = "";
688+
689+
std::string ltype = Notification_Type_Desc(ntype, 1);
690+
691+
time_t atime = mytime(NULL);
692+
atime -= m_NotificationSwitchInterval;
693+
694+
std::vector<_tNotification>::const_iterator itt;
695+
for (itt = notifications.begin(); itt != notifications.end(); ++itt)
696+
{
697+
if ((atime >= itt->LastSend) || (itt->SendAlways)) //emergency always goes true
698+
{
699+
std::vector<std::string> splitresults;
700+
StringSplit(itt->Params, ";", splitresults);
701+
if (splitresults.size() < 1)
702+
continue; //impossible
703+
std::string atype = splitresults[0];
704+
705+
bool bSendNotification = false;
706+
707+
if (atype == ltype)
708+
{
709+
msg = devicename;
710+
if (ntype == NTYPE_SWITCH_ON)
711+
{
712+
if (splitresults.size() < 3)
713+
continue; //impossible
714+
bool bWhenEqual = (splitresults[1] == "=");
715+
int iLevel = atoi(splitresults[2].c_str());
716+
if (!bWhenEqual || iLevel < 10 || iLevel > 100)
717+
continue; //invalid
718+
719+
if (llevel == iLevel)
720+
{
721+
bSendNotification = true;
722+
std::string sLevel = boost::lexical_cast<std::string>(llevel);
723+
szExtraData += "Status=Level " + sLevel + "|";
724+
725+
if (switchtype == STYPE_Selector)
726+
{
727+
std::map<std::string, std::string> options = m_sql.BuildDeviceOptions(sOptions);
728+
std::string levelNames = options["LevelNames"];
729+
std::vector<std::string> splitresults;
730+
StringSplit(levelNames, "|", splitresults);
731+
msg += " >> " + splitresults[(llevel / 10)];
732+
}
733+
else
734+
msg += " >> LEVEL " + sLevel;
735+
}
736+
}
737+
else
738+
{
739+
bSendNotification = true;
740+
szExtraData += "Status=Off|";
741+
msg += " >> OFF";
742+
}
743+
}
744+
if (bSendNotification)
745+
{
746+
if (!itt->CustomMessage.empty())
747+
msg = itt->CustomMessage;
748+
SendMessageEx(itt->ActiveSystems, msg, msg, szExtraData, itt->Priority, std::string(""), true);
749+
TouchNotification(itt->ID);
750+
}
751+
}
752+
}
753+
return true;
754+
}
755+
667756
bool CNotificationHelper::CheckAndHandleRainNotification(
668757
const unsigned long long Idx,
669758
const std::string &devicename,

notifications/NotificationHelper.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ class CNotificationHelper {
6868
const unsigned long long Idx,
6969
const std::string &devicename,
7070
const _eNotificationTypes ntype);
71+
bool CheckAndHandleSwitchNotification(
72+
const unsigned long long Idx,
73+
const std::string & devicename,
74+
const _eNotificationTypes ntype,
75+
const int llevel);
7176
bool CheckAndHandleRainNotification(
7277
const unsigned long long Idx,
7378
const std::string &devicename,

www/app/LightsController.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,9 +1355,9 @@ define(['app'], function (app) {
13551355
});
13561356
});
13571357
// Limit level length to levelNamesMaxLength
1358-
$("#newselectorlevelbutton").prop("disabled", false).removeClass("ui-state-disabled");
1358+
$("#lightcontent #newselectorlevelbutton").prop("disabled", false).removeClass("ui-state-disabled");
13591359
if (levelNames.length === levelNamesMaxLength) {
1360-
$("#newselectorlevelbutton").prop("disabled", true).addClass("ui-state-disabled");
1360+
$("#lightcontent #newselectorlevelbutton").prop("disabled", true).addClass("ui-state-disabled");
13611361
}
13621362
};
13631363

@@ -2888,9 +2888,9 @@ define(['app'], function (app) {
28882888
}
28892889
}
28902890
if (item.Notifications == "true")
2891-
xhtm+='<a class="btnsmall-sel" onclick="ShowNotifications(' + item.idx + ',\'' + escape(item.Name) + '\', \'#lightcontent\', \'ShowLights\');" data-i18n="Notifications">Notifications</a>';
2891+
xhtm+='<a class="btnsmall-sel" onclick="ShowNotifications(' + item.idx + ',\'' + escape(item.Name) + '\', \'#lightcontent\', \'ShowLights\',' + bIsDimmer + ',\'' + item.Type + '\'' + ', \'' + item.SubType + '\');" data-i18n="Notifications">Notifications</a>';
28922892
else
2893-
xhtm+='<a class="btnsmall" onclick="ShowNotifications(' + item.idx + ',\'' + escape(item.Name) + '\', \'#lightcontent\', \'ShowLights\');" data-i18n="Notifications">Notifications</a>';
2893+
xhtm+='<a class="btnsmall" onclick="ShowNotifications(' + item.idx + ',\'' + escape(item.Name) + '\', \'#lightcontent\', \'ShowLights\',' + bIsDimmer + ',\'' + item.Type + '\'' + ', \'' + item.SubType + '\');" data-i18n="Notifications">Notifications</a>';
28942894
}
28952895
xhtm+=
28962896
'</td>\n' +

www/index.html

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,6 +1299,33 @@ <h1 id="theader" data-i18n="Usage this Year">Usage this Year</h1>
12991299
<td align="right" style="width:160px"><label for="combotype"><span data-i18n="Type"></span>:</label></td>
13001300
<td><select id="combotype" style="width:120px" class="combobox ui-corner-all"></select></td>
13011301
</tr>
1302+
<tr id="notilevel">
1303+
<td align="right" style="width:160px"><label for="combolevel"><span data-i18n="Level"></span>:</label></td>
1304+
<td>
1305+
<select id="combolevel" style="width:70px" class="combobox ui-corner-all">
1306+
<option value="5">5%</option>
1307+
<option value="10">10%</option>
1308+
<option value="15">15%</option>
1309+
<option value="20">20%</option>
1310+
<option value="25">25%</option>
1311+
<option value="30">30%</option>
1312+
<option value="35">35%</option>
1313+
<option value="40">40%</option>
1314+
<option value="45">45%</option>
1315+
<option value="50">50%</option>
1316+
<option value="55">55%</option>
1317+
<option value="60">60%</option>
1318+
<option value="65">65%</option>
1319+
<option value="70">70%</option>
1320+
<option value="75">75%</option>
1321+
<option value="80">80%</option>
1322+
<option value="85">85%</option>
1323+
<option value="90">90%</option>
1324+
<option value="95">95%</option>
1325+
<option value="100">100%</option>
1326+
</select>
1327+
</td>
1328+
</tr>
13021329
<tr id="notiwhen">
13031330
<td align="right"><label for="combowhen"><span data-i18n="When"></span>:</label></td>
13041331
<td><select id="combowhen" style="width:120px" class="combobox ui-corner-all">

www/js/domoticz.js.gz

1 KB
Binary file not shown.

0 commit comments

Comments
 (0)