...as the basis for a new driver (for the same device) to change it from a "pull" to a "push". The existing driver works fine, but I'm using this as a learning experience.
For the first step, I simply added a parse method to the parent driver to log the incoming data...
I deleted the device, re-added it using my modified driver, etc. The driver has a preference field for the device's IP address, and it is set correctly.
Whenever the server pushes data, it gets to HE, but I get the log message...
Received data from 192.168.1.150, no matching device found for 192.168.1.150...
Is there anything I need to do to "register" the driver to the server's IP address other than the existence of the IP address preference field?
Here's what the XML data looks like when viewed via the OW-Server's web admin page. Note that the following data is not a view of the exact same data in the log above, i.e., the snapshots were at different times...
Concentrating on the relative humidity and temperature values (circled in blue in the log snapshot above), how do I get those values updated on the child screen? Note that there is one child driver for each sensor, and there can be up to 22 sensors. I only have one sensor at this time, but there will be several more when this stuff "goes production" in my home's crawl space. It looks like each push will contain data for all the sensors.
I'm looking for a sample LAN-based device driver that receives data (i.e., the LAN device pushes data to HE on port 39501) in XML format. It would be especially helpful if the driver consists of a parent driver and multiple child drivers, and the LAN device pushes data for all child drivers/devices on every push.
I've looked at the Ecowitt driver and learned a lot from it. However, it's not XML-based. The biggest problem I'm having now is understanding how to get values out of the XML data and into variables that can be processed by the parent and/or child drivers.
I read the new "Building a LAN or Cloud Driver" topic in the doc, but all it says about this stuff is...
The data (passed in as the first and only parameter) can then be further processed (e.g., with parseLanMessage()) or dealt with as necessary.
I need to know what to do with the data after the parseLanMessage() method call, and how to "deal with it as necessary".
The parse(String message) method receives the full HTTP request string.
parseLanMessage(String message) is a helper that breaks it into a Map of its constituent parts, and you are probably most interested in the body member, which will contain the raw XML response as a String.
Then you can use the nice Groovy parsing functions described in this tutorial to convert the XML string into something you can work with to actually get at the data in the response.
So, try something like this:
def parse(String message)
{
String xmlStr = parseLanMessage(message)?.body
// do as needed with xmlStr according to the tutorial above
}
Incidentally, I just noticed that Hubitat has a built in method called GPathResult parseXML(String stringToParse), which is probably just a shorthand for XmlSlurper. But I usually use the Groovy libraries directly just so it's clear to me exactly what is executing.
@tomw I realize you replied to the other thread I started to ask for a sample LAN driver, so you probably didn't see my earlier posts in this thread. Late yesterday, I had already gotten to the point of extracting the body of the XML (although using a little different code to do so). So this is what the body looks like in the live log...
What I'm having a hard time figuring out is the syntax for accessing individual elements in the XML. Using the XML data screen shot above to see the elements, how do I write the value of "PollCount" in the parent element to the log using log.debug? How do I write the value of "Name" in the child element? What if there are multiple child elements?
That looks like the full HTTP request, including headers and the rest). You will need to get just the XML document out of that. I'd recommend the method I described above.
Then you can traverse the XML document as described in the tutorial that I linked above. Did you try what was described there? Please share your code and describe more about how it is failing.
I only see one thread/topic on this question now. Your first post "there" (now a few posts up here) was a duplicate of the post above this, so I merged the two into the same, existing topic to make things easier for everyone. (Also, please don't make duplicate posts. )
@bertabcd1234 I started the other thread because I was specifically looking for an existing driver that did the "basic LAN stuff" using XML data being pushed to HE, etc., that I could learn from and hopefully reduce the number or questions in this thread.
My concern was that people got tired of reading this thread (I can get a little verbose at times), and/or lost interest. That's why I specifically asked for a sample LAN driver in the other thread (hopefully without going into too much detail). I hadn't asked for a sample driver in this thread, so I didn't think of it as a duplicate.
What you need to do is split the body across boundary, then trim non-XML content, then parse each one.
def parse(String message)
{
Map lanMsg = parseLanMessage(message)
String bodyStr = lanMsg?.body
String boundaryStr = lanMsg?.headers?.boundary
List bodyContents = bodyStr?.tokenize(boundaryStr)
bodyContents.each { logXml(it) }
// in the step above, strip the extra parts that aren't XML off
// ... this string parsing is your task to figure out
// the result is mocked up here:
def xml = '''
<Devices-Detail-Response xmlns="http://www.embeddeddatasystems.com/schema/owserver" xmlns:xsi="http://www.w3.org/2002/XMLSchema-instance">
<PollCount>18500</PollCount>
</Devices-Detail-Response>'''
List onlyXmlContents = [xml]
// then do something like this with what's left
onlyXmlContents.each
{
def xmlObj = parseXML(it)
log.debug xmlObj.PollCount
}
}
@tomw I copied your code and added the escapeXml method for debugging purposes. I understand that I need to somehow get rid of the data that is before and after the Devices-Detail-Response element, but the code didn't get very far. Here's the log showing the exception and the first part of the XML data...
Then check to make sure boundaryStr isn't null before you use it on the next line. You may want to print it to the log just to make sure the value is as expected.
@bertabcd1234 I still can't get this to work. Can you close this thread so I can open a new thread specifically about the problem I'm having trying to parse/process the XML code coming from the LAN device server? I'm concerned that the general nature of the topic and the initial posts with different questions are resulting in people ignoring this thread now (except for @tomw, who has been graciously replying).