Page 2 of 2

Re: Plugin: Travel Times

Posted: Sunday 04 February 2018 22:43
by clubeddie
I am using Domoticz on a Synology. Any change to get it working there?
I placed the extracted zip folder in the plugins directory, /volume1/@appstore/domoticz/var/plugins

But hardware is not visible (also after restart), maybe i am doing something wrong, maybe it is not possible

Re: Plugin: Travel Times

Posted: Monday 05 February 2018 8:48
by febalci
@clubeddie:

You have to have the version with Python Plugin support Domoticz from jadahl. Also, do not forget to use "chmod +x plugin.py" on the file. Is Python3 package installed on your Synology?

@mastair:

When using onheartbeat more than 50 seconds, you will see this error. I use a counter variable and 10 seconds heartbeat, so when the counter reaches a certain value from the heartbeat, it then executes the necessary todo; then you will not see an error. I am writing a new plugin for my own use on travel times, once it is ready i will share it here.

Re: Plugin: Travel Times

Posted: Monday 05 February 2018 12:24
by clubeddie
febalci wrote: Monday 05 February 2018 8:48 @clubeddie:

You have to have the version with Python Plugin support Domoticz from jadahl. Also, do not forget to use "chmod +x plugin.py" on the file. Is Python3 package installed on your Synology?
I can confirm it is working after updating my domoticz with the python plugin update. So thank you, now waiting for the xiaomi gateway and check if i can build a blockly to change the color of the ring acoording to the percentage of the traffic :lol:

Re: Plugin: Travel Times

Posted: Saturday 10 February 2018 12:29
by febalci
For those who have:

Code: Select all

Error: Travel (16) thread seems to have ended unexpectedly
Errors due to long poll times; try this plugin.py:

Code: Select all

"""
<plugin key="TravelTimes" name="Travel Times" author="mastair" version="1.0.0">
    <params>
        <param field="Mode1" label="From address" width="200px" required="true"/>
        <param field="Mode2" label="To address" width="200px" required="true"/>
        <param field="Mode5" label="Google API Key" width="200px" required="true"/>
        <param field="Mode6" label="Polling interval (min)" width="40px" required="true"/>
    </params>
</plugin>
"""
import Domoticz
import json
import urllib.request
import urllib.parse

#variables
mode            = "driving"
directionsURL   = "https://maps.googleapis.com/maps/api/directions/json?origin=%s&destination=%s=&transit_mode=driving&departure_time=now&key=%s"
defaultPollingInterval = 2 #Changed From 120 seconds to 2 minutes
pollPeriod = 0 #Added
pollCount = 0 #Added

def onStart():
    global pollCount, pollPeriod
    Domoticz.Debug("onStart called")

    if (len(Devices) == 0):
        Domoticz.Device(Name="Travel time", Unit=1, TypeName="Custom", Options={"Custom": "1;minutes"}).Create()
        Domoticz.Device(Name="Travel delay", Unit=2, TypeName="Custom", Options={"Custom": "1;%"}).Create()

    pollPeriod = 6 * int(Parameters["Mode6"]) #Added, convert minutes to 10 sec periods
    pollCount = pollPeriod - 1 #Added 

    Domoticz.Heartbeat(10) #Changed to 10 sec intervals

    return True

def onHeartbeat():
    global pollCount, pollPeriod


    if pollCount >= pollPeriod: #Added
        updateSensors()
        pollCount = 0 #Reset Pollcount Added
    else: #Added
        pollCount = pollCount + 1 #Added, count until full
    return True

def updateSensors():
    try:
        Domoticz.Debug("getDelay called")

        # Call Directions API
        url = directionsURL % (urllib.parse.quote(fromAddress()), urllib.parse.quote(toAddress()), apiKey())
        request = urllib.request.urlopen(url)
        data = json.loads(request.read().decode('utf-8'))

        if "error_message" in data:
            Domoticz.Error("Error retrieving travel times from Google Maps API: %s" % data["error_message"])
            return
        
        # Get durations
        normal_duration = int(data["routes"][0]["legs"][0]["duration"]["value"]/60.0)
        current_duration = int(data["routes"][0]["legs"][0]["duration_in_traffic"]["value"]/60.0)
        delay = round((float)(current_duration - normal_duration)/normal_duration*100)

        # Update devices
        if 1 in Devices:
            Devices[1].Update(nValue = current_duration, sValue = str(current_duration))

        if 2 in Devices:
            Devices[2].Update(nValue = delay, sValue = str(delay))
    except:
        Domoticz.Error("Error retrieving travel times from Google Maps API")

####### GETTERS FOR PARAMETERS ########
def pollingInterval():
    try:
        return int(Parameters["Mode6"])
    except:
        Domoticz.Error("Error converting polling interval to integer, using %s seconds as polling interval" %defaultPollingInterval)
        return defaultPollingInterval

def fromAddress():
    return Parameters["Mode1"]

def toAddress():
    return Parameters["Mode2"]

def apiKey():
    return Parameters["Mode5"]

############## NOT USED ##############
def onStop():
    return True

def onConnect(Status, Description):
    return True

def onMessage(Data, Status, Extra):
    return True

def onCommand(Unit, Command, Level, Hue):
    return True

def onNotification(Name, Subject, Text, Status, Priority, Sound, ImageFile):
    return True

def onDisconnect():
    return True
Please note that polling period is converted into minutes instead of seconds. So now it goes to heartbeat every 10 seconds and check if polling period completed; if not just count; if completed then check google api.

Re: Plugin: Travel Times

Posted: Saturday 10 February 2018 14:02
by tezzlicious
febalci wrote: Saturday 10 February 2018 12:29 For those who have:

Code: Select all

Error: Travel (16) thread seems to have ended unexpectedly
Errors due to long poll times; try this plugin.py:

Code: Select all

"""
<plugin key="TravelTimes" name="Travel Times" author="mastair" version="1.0.0">
    <params>
        <param field="Mode1" label="From address" width="200px" required="true"/>
        <param field="Mode2" label="To address" width="200px" required="true"/>
        <param field="Mode5" label="Google API Key" width="200px" required="true"/>
        <param field="Mode6" label="Polling interval (min)" width="40px" required="true"/>
    </params>
</plugin>
"""
import Domoticz
import json
import urllib.request
import urllib.parse

#variables
mode            = "driving"
directionsURL   = "https://maps.googleapis.com/maps/api/directions/json?origin=%s&destination=%s=&transit_mode=driving&departure_time=now&key=%s"
defaultPollingInterval = 2 #Changed From 120 seconds to 2 minutes
pollPeriod = 0 #Added
pollCount = 0 #Added

def onStart():
    Domoticz.Debug("onStart called")

    if (len(Devices) == 0):
        Domoticz.Device(Name="Travel time", Unit=1, TypeName="Custom", Options={"Custom": "1;minutes"}).Create()
        Domoticz.Device(Name="Travel delay", Unit=2, TypeName="Custom", Options={"Custom": "1;%"}).Create()

    self.pollPeriod = 6 * int(Parameters["Mode6"]) #Added, convert minutes to 10 sec periods
    self.pollCount = self.pollPeriod - 1 #Added 
    Domoticz.Heartbeat(10) #Changed to 10 sec intervals

    return True

def onHeartbeat():
    if self.pollCount >= self.pollPeriod: #Added
        updateSensors()
        self.pollCount = 0 #Reset Pollcount Added
    else: #Added
        self.pollCount = self.pollCount + 1 #Added, count until full
    return True

def updateSensors():
    try:
        Domoticz.Debug("getDelay called")

        # Call Directions API
        url = directionsURL % (urllib.parse.quote(fromAddress()), urllib.parse.quote(toAddress()), apiKey())
        request = urllib.request.urlopen(url)
        data = json.loads(request.read().decode('utf-8'))

        if "error_message" in data:
            Domoticz.Error("Error retrieving travel times from Google Maps API: %s" % data["error_message"])
            return
        
        # Get durations
        normal_duration = int(data["routes"][0]["legs"][0]["duration"]["value"]/60.0)
        current_duration = int(data["routes"][0]["legs"][0]["duration_in_traffic"]["value"]/60.0)
        delay = round((float)(current_duration - normal_duration)/normal_duration*100)

        # Update devices
        if 1 in Devices:
            Devices[1].Update(nValue = current_duration, sValue = str(current_duration))

        if 2 in Devices:
            Devices[2].Update(nValue = delay, sValue = str(delay))
    except:
        Domoticz.Error("Error retrieving travel times from Google Maps API")

####### GETTERS FOR PARAMETERS ########
def pollingInterval():
    try:
        return int(Parameters["Mode6"])
    except:
        Domoticz.Error("Error converting polling interval to integer, using %s seconds as polling interval" %defaultPollingInterval)
        return defaultPollingInterval

def fromAddress():
    return Parameters["Mode1"]

def toAddress():
    return Parameters["Mode2"]

def apiKey():
    return Parameters["Mode5"]

############## NOT USED ##############
def onStop():
    return True

def onConnect(Status, Description):
    return True

def onMessage(Data, Status, Extra):
    return True

def onCommand(Unit, Command, Level, Hue):
    return True

def onNotification(Name, Subject, Text, Status, Priority, Sound, ImageFile):
    return True

def onDisconnect():
    return True
Please note that polling period is converted into minutes instead of seconds. So now it goes to heartbeat every 10 seconds and check if polling period completed; if not just count; if completed then check google api.
On the latest beta:

Code: Select all

'onStart' failed 'NameError':'name 'self' is not defined'.

Re: Plugin: Travel Times

Posted: Saturday 10 February 2018 15:58
by febalci
tezzlicious wrote: Saturday 10 February 2018 14:02
On the latest beta:

Code: Select all

'onStart' failed 'NameError':'name 'self' is not defined'.
Sorry, corrected in the previous message code section.

Re: Plugin: Travel Times

Posted: Sunday 11 February 2018 20:46
by tezzlicious
febalci wrote: Saturday 10 February 2018 15:58
tezzlicious wrote: Saturday 10 February 2018 14:02
On the latest beta:

Code: Select all

'onStart' failed 'NameError':'name 'self' is not defined'.
Sorry, corrected in the previous message code section.
Works like a charm now :D Thanks!

Re: Plugin: Travel Times

Posted: Tuesday 23 April 2019 7:53
by maryannlee9
I am not a topic starter, but had just the same issue. Everything works greatly now due to advices from this thread, I wanted to create a similar topic about travel times, too.

Re: Plugin: Travel Times

Posted: Tuesday 23 April 2019 8:50
by Dnpwwo
Not a bug in Domoticz, it is a behavior designed to pick up 'hardware' related processes (including Python plugins) that have hung or are not responding and is required for troubleshooting.

The plugin wiki documents the 'Heartbeat' functionality and states:
Set the heartbeat interval in seconds, default 10 seconds. Values greater than 30 seconds will cause a message to be regularly logged about the plugin not responding. The plugin will actually function correctly with values greater than 30 though.
If you want to ensure you never get the message, set the value to less than 30.

If the plugin only needs to take action every 5 or 10 minutes then it can be modified to check if is time to act every 10 seconds during a heartbeat using a timer or countdown