Plugin: Travel Times

Python and python framework

Moderator: leecollings

clubeddie
Posts: 80
Joined: Saturday 19 March 2016 21:12
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Plugin: Travel Times

Post 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
febalci
Posts: 331
Joined: Monday 03 July 2017 19:58
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Plugin: Travel Times

Post 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.
clubeddie
Posts: 80
Joined: Saturday 19 March 2016 21:12
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Plugin: Travel Times

Post 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:
febalci
Posts: 331
Joined: Monday 03 July 2017 19:58
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Plugin: Travel Times

Post 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.
Last edited by febalci on Saturday 10 February 2018 15:57, edited 1 time in total.
tezzlicious
Posts: 39
Joined: Saturday 09 April 2016 13:47
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Contact:

Re: Plugin: Travel Times

Post 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'.
febalci
Posts: 331
Joined: Monday 03 July 2017 19:58
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Plugin: Travel Times

Post 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.
tezzlicious
Posts: 39
Joined: Saturday 09 April 2016 13:47
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Contact:

Re: Plugin: Travel Times

Post 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!
maryannlee9
Posts: 2
Joined: Monday 08 April 2019 11:04
Target OS: Windows
Domoticz version:

Re: Plugin: Travel Times

Post 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.
User avatar
Dnpwwo
Posts: 819
Joined: Sunday 23 March 2014 9:00
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Melbourne, Australia
Contact:

Re: Plugin: Travel Times

Post 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
The reasonable man adapts himself to the world; the unreasonable one persists to adapt the world to himself. Therefore all progress depends on the unreasonable man. George Bernard Shaw
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest