update esppilight lib
content of the library is not filtered on 433mhz only
This commit is contained in:
1 parent
a275e48ee1
commit
67dd7ac078
1030 files changed
+203335
-116
No files matched your search
@@ -0,0 +1,444 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ManufacturerSpecific.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_MANUFACTURER_SPECIFIC
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "ManufacturerSpecific.h"
|
||||
#include "../tinyxml.h"
|
||||
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Options.h"
|
||||
#include "../Manager.h"
|
||||
#include "../Driver.h"
|
||||
#include "../Notification.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueStore.h"
|
||||
#include "../value_classes/ValueString.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum ManufacturerSpecificCmd
|
||||
{
|
||||
ManufacturerSpecificCmd_Get = 0x04,
|
||||
ManufacturerSpecificCmd_Report = 0x05
|
||||
};
|
||||
|
||||
map<uint16,string> ManufacturerSpecific::s_manufacturerMap;
|
||||
map<int64,ManufacturerSpecific::Product*> ManufacturerSpecific::s_productMap;
|
||||
bool ManufacturerSpecific::s_bXmlLoaded = false;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ManufacturerSpecific::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ManufacturerSpecific::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( ( _requestFlags & RequestFlag_Static ) && HasStaticRequest( StaticRequest_Values ) )
|
||||
{
|
||||
return RequestValue( _requestFlags, 0, _instance, _queue );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ManufacturerSpecific::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ManufacturerSpecific::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _dummy1, // = 0 (not used)
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _instance != 1 )
|
||||
{
|
||||
// This command class doesn't work with multiple instances
|
||||
return false;
|
||||
}
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
Msg* msg = new Msg( "ManufacturerSpecificCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( ManufacturerSpecificCmd_Get );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "ManufacturerSpecificCmd_Get Not Supported on this node");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
string ManufacturerSpecific::SetProductDetails
|
||||
(
|
||||
Node* node,
|
||||
uint16 manufacturerId,
|
||||
uint16 productType,
|
||||
uint16 productId
|
||||
)
|
||||
{
|
||||
char str[64];
|
||||
|
||||
if (!s_bXmlLoaded) LoadProductXML();
|
||||
|
||||
snprintf( str, sizeof(str), "Unknown: id=%.4x", manufacturerId );
|
||||
string manufacturerName = str;
|
||||
|
||||
snprintf( str, sizeof(str), "Unknown: type=%.4x, id=%.4x", productType, productId );
|
||||
string productName = str;
|
||||
|
||||
string configPath = "";
|
||||
|
||||
// Try to get the real manufacturer and product names
|
||||
map<uint16,string>::iterator mit = s_manufacturerMap.find( manufacturerId );
|
||||
if( mit != s_manufacturerMap.end() )
|
||||
{
|
||||
// Replace the id with the real name
|
||||
manufacturerName = mit->second;
|
||||
|
||||
// Get the product
|
||||
map<int64,Product*>::iterator pit = s_productMap.find( Product::GetKey( manufacturerId, productType, productId ) );
|
||||
if( pit != s_productMap.end() )
|
||||
{
|
||||
productName = pit->second->GetProductName();
|
||||
configPath = pit->second->GetConfigPath();
|
||||
}
|
||||
}
|
||||
|
||||
// Set the values into the node
|
||||
|
||||
// Only set the manufacturer and product name if they are
|
||||
// empty - we don't want to overwrite any user defined names.
|
||||
if( node->GetManufacturerName() == "" )
|
||||
{
|
||||
node->SetManufacturerName( manufacturerName );
|
||||
}
|
||||
|
||||
if( node->GetProductName() == "" )
|
||||
{
|
||||
node->SetProductName( productName );
|
||||
}
|
||||
|
||||
snprintf( str, sizeof(str), "%.4x", manufacturerId );
|
||||
node->SetManufacturerId( str );
|
||||
|
||||
snprintf( str, sizeof(str), "%.4x", productType );
|
||||
node->SetProductType( str );
|
||||
|
||||
snprintf( str, sizeof(str), "%.4x", productId );
|
||||
node->SetProductId( str );
|
||||
|
||||
return configPath;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ManufacturerSpecific::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ManufacturerSpecific::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if( ManufacturerSpecificCmd_Report == (ManufacturerSpecificCmd)_data[0] )
|
||||
{
|
||||
|
||||
// first two bytes are manufacturer id code
|
||||
uint16 manufacturerId = (((uint16)_data[1])<<8) | (uint16)_data[2];
|
||||
|
||||
// next four are product type and product id
|
||||
uint16 productType = (((uint16)_data[3])<<8) | (uint16)_data[4];
|
||||
uint16 productId = (((uint16)_data[5])<<8) | (uint16)_data[6];
|
||||
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
// Attempt to create the config parameters
|
||||
string configPath = SetProductDetails( node, manufacturerId, productType, productId);
|
||||
if( configPath.size() > 0 )
|
||||
{
|
||||
LoadConfigXML( node, configPath );
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received manufacturer specific report from node %d: Manufacturer=%s, Product=%s",
|
||||
GetNodeId(), node->GetManufacturerName().c_str(), node->GetProductName().c_str() );
|
||||
ClearStaticRequest( StaticRequest_Values );
|
||||
node->m_manufacturerSpecificClassReceived = true;
|
||||
}
|
||||
|
||||
// Notify the watchers of the name changes
|
||||
Notification* notification = new Notification( Notification::Type_NodeNaming );
|
||||
notification->SetHomeAndNodeIds( GetHomeId(), GetNodeId() );
|
||||
GetDriver()->QueueNotification( notification );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ManufacturerSpecific::LoadProductXML>
|
||||
// Load the XML that maps manufacturer and product IDs to human-readable names
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ManufacturerSpecific::LoadProductXML
|
||||
(
|
||||
)
|
||||
{
|
||||
s_bXmlLoaded = true;
|
||||
|
||||
// Parse the Z-Wave manufacturer and product XML file.
|
||||
string configPath;
|
||||
Options::Get()->GetOptionAsString( "ConfigPath", &configPath );
|
||||
|
||||
string filename = configPath + "manufacturer_specific.xml";
|
||||
|
||||
TiXmlDocument* pDoc = new TiXmlDocument();
|
||||
if( !pDoc->LoadFile( filename.c_str(), TIXML_ENCODING_UTF8 ) )
|
||||
{
|
||||
delete pDoc;
|
||||
Log::Write( LogLevel_Info, "Unable to load %s", filename.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
TiXmlElement const* root = pDoc->RootElement();
|
||||
|
||||
char const* str;
|
||||
char* pStopChar;
|
||||
|
||||
TiXmlElement const* manufacturerElement = root->FirstChildElement();
|
||||
while( manufacturerElement )
|
||||
{
|
||||
str = manufacturerElement->Value();
|
||||
if( str && !strcmp( str, "Manufacturer" ) )
|
||||
{
|
||||
// Read in the manufacturer attributes
|
||||
str = manufacturerElement->Attribute( "id" );
|
||||
if( !str )
|
||||
{
|
||||
Log::Write( LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing manufacturer id attribute", manufacturerElement->Row() );
|
||||
delete pDoc;
|
||||
return false;
|
||||
}
|
||||
uint16 manufacturerId = (uint16)strtol( str, &pStopChar, 16 );
|
||||
|
||||
str = manufacturerElement->Attribute( "name" );
|
||||
if( !str )
|
||||
{
|
||||
Log::Write( LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing manufacturer name attribute", manufacturerElement->Row() );
|
||||
delete pDoc;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add this manufacturer to the map
|
||||
s_manufacturerMap[manufacturerId] = str;
|
||||
|
||||
// Parse all the products for this manufacturer
|
||||
TiXmlElement const* productElement = manufacturerElement->FirstChildElement();
|
||||
while( productElement )
|
||||
{
|
||||
str = productElement->Value();
|
||||
if( str && !strcmp( str, "Product" ) )
|
||||
{
|
||||
str = productElement->Attribute( "type" );
|
||||
if( !str )
|
||||
{
|
||||
Log::Write( LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing product type attribute", productElement->Row() );
|
||||
delete pDoc;
|
||||
return false;
|
||||
}
|
||||
uint16 productType = (uint16)strtol( str, &pStopChar, 16 );
|
||||
|
||||
str = productElement->Attribute( "id" );
|
||||
if( !str )
|
||||
{
|
||||
Log::Write( LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing product id attribute", productElement->Row() );
|
||||
delete pDoc;
|
||||
return false;
|
||||
}
|
||||
uint16 productId = (uint16)strtol( str, &pStopChar, 16 );
|
||||
|
||||
str = productElement->Attribute( "name" );
|
||||
if( !str )
|
||||
{
|
||||
Log::Write( LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing product name attribute", productElement->Row() );
|
||||
delete pDoc;
|
||||
return false;
|
||||
}
|
||||
string productName = str;
|
||||
|
||||
// Optional config path
|
||||
string configPath;
|
||||
str = productElement->Attribute( "config" );
|
||||
if( str )
|
||||
{
|
||||
configPath = str;
|
||||
}
|
||||
|
||||
// Add the product to the map
|
||||
Product* product = new Product( manufacturerId, productType, productId, productName, configPath );
|
||||
if ( s_productMap[product->GetKey()] != NULL )
|
||||
{
|
||||
Product *c = s_productMap[product->GetKey()];
|
||||
Log::Write( LogLevel_Info, "Product name collision: %s type %x id %x manufacturerid %x, collides with %s, type %x id %x manufacturerid %x", productName.c_str(), productType, productId, manufacturerId, c->GetProductName().c_str(), c->GetProductType(), c->GetProductId(), c->GetManufacturerId());
|
||||
delete product;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_productMap[product->GetKey()] = product;
|
||||
}
|
||||
}
|
||||
|
||||
// Move on to the next product.
|
||||
productElement = productElement->NextSiblingElement();
|
||||
}
|
||||
}
|
||||
|
||||
// Move on to the next manufacturer.
|
||||
manufacturerElement = manufacturerElement->NextSiblingElement();
|
||||
}
|
||||
|
||||
delete pDoc;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ManufacturerSpecific::UnloadProductXML>
|
||||
// Free the XML that maps manufacturer and product IDs
|
||||
//-----------------------------------------------------------------------------
|
||||
void ManufacturerSpecific::UnloadProductXML
|
||||
(
|
||||
)
|
||||
{
|
||||
if (s_bXmlLoaded)
|
||||
{
|
||||
map<int64,Product*>::iterator pit = s_productMap.begin();
|
||||
while( !s_productMap.empty() )
|
||||
{
|
||||
delete pit->second;
|
||||
s_productMap.erase( pit );
|
||||
pit = s_productMap.begin();
|
||||
}
|
||||
|
||||
map<uint16,string>::iterator mit = s_manufacturerMap.begin();
|
||||
while( !s_manufacturerMap.empty() )
|
||||
{
|
||||
s_manufacturerMap.erase( mit );
|
||||
mit = s_manufacturerMap.begin();
|
||||
}
|
||||
|
||||
s_bXmlLoaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ManufacturerSpecific::LoadConfigXML>
|
||||
// Try to find and load an XML file describing the device's config params
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ManufacturerSpecific::LoadConfigXML
|
||||
(
|
||||
Node* _node,
|
||||
string const& _configXML
|
||||
)
|
||||
{
|
||||
string configPath;
|
||||
Options::Get()->GetOptionAsString( "ConfigPath", &configPath );
|
||||
|
||||
string filename = configPath + _configXML;
|
||||
|
||||
TiXmlDocument* doc = new TiXmlDocument();
|
||||
Log::Write( LogLevel_Info, _node->GetNodeId(), " Opening config param file %s", filename.c_str() );
|
||||
if( !doc->LoadFile( filename.c_str(), TIXML_ENCODING_UTF8 ) )
|
||||
{
|
||||
delete doc;
|
||||
Log::Write( LogLevel_Info, _node->GetNodeId(), "Unable to find or load Config Param file %s", filename.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
Node::QueryStage qs = _node->GetCurrentQueryStage();
|
||||
if( qs == Node::QueryStage_ManufacturerSpecific1 )
|
||||
{
|
||||
_node->ReadDeviceProtocolXML( doc->RootElement() );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !_node->m_manufacturerSpecificClassReceived )
|
||||
{
|
||||
_node->ReadDeviceProtocolXML( doc->RootElement() );
|
||||
}
|
||||
_node->ReadCommandClassesXML( doc->RootElement() );
|
||||
}
|
||||
|
||||
delete doc;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ManufacturerSpecific::ReLoadConfigXML>
|
||||
// Reload previously discovered device configuration.
|
||||
//-----------------------------------------------------------------------------
|
||||
void ManufacturerSpecific::ReLoadConfigXML
|
||||
(
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
if (!s_bXmlLoaded) LoadProductXML();
|
||||
|
||||
uint16 manufacturerId = (uint16)strtol( node->GetManufacturerId().c_str(), NULL, 16 );
|
||||
uint16 productType = (uint16)strtol( node->GetProductType().c_str(), NULL, 16 );
|
||||
uint16 productId = (uint16)strtol( node->GetProductId().c_str(), NULL, 16 );
|
||||
|
||||
map<uint16,string>::iterator mit = s_manufacturerMap.find( manufacturerId );
|
||||
if( mit != s_manufacturerMap.end() )
|
||||
{
|
||||
map<int64,Product*>::iterator pit = s_productMap.find( Product::GetKey( manufacturerId, productType, productId ) );
|
||||
if( pit != s_productMap.end() )
|
||||
{
|
||||
string configPath = pit->second->GetConfigPath();
|
||||
if( configPath.size() > 0 )
|
||||
{
|
||||
LoadConfigXML( node, configPath );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user