Select to view content in your preferred language

Road Closure Solution producing error in Waze

395
5
3 weeks ago
Jennifer_Parmeley
Frequent Contributor

I deployed Road Closures for our organization so we could use RC schema to feed Waze. There's a push to use Waze in our area.

During testing I found an error in the Waze Partner space. The "Work Area" value is not accepted by Waze, it appears, but I'll be honest that reading an xsd is not something I have a great deal of experience doing. I'm not sure at this point if I should update the domain list in the ESRI solution (what else will this break?) or try to add the subtype information that Waze might be looking for. I had a support ticket with ESRI about the solution and they were very specific about schema changes and not making them. I've made several because we need them. I cannot 100% redesign our product for our smaller community, the change needs to happen more slowly. We are only using the feature service (and related view) in our local solution, so I don't care if the map and ExB part of the solution don't work, I've got my own solutions there, but I want Waze to get the data we are sending.

Has anyone else found this? Any suggestions on getting this to work? Maybe I'm missing something basic?!

Jennifer_Parmeley_0-1757702373530.png

Jennifer_Parmeley_2-1757702677725.pngJennifer_Parmeley_3-1757702699510.png

 

Updating the feature to a "hazard" does not fix the error in Waze. Hazard is in the solution and Waze xsd.

Jennifer_Parmeley_4-1757703601738.png

part of the Waze xsd, with I think, the related info.

Jennifer_Parmeley_1-1757702558617.png

 

 




5 Replies
Joshua-Young
Honored Contributor

Where did the value "Work Area" come from? We have been using version 2.0 of the Road Closure solution and the only types we have are Construction, Event, and Hazard. Esri changed the data schema from version 1.0 to 2.0 and it is no longer compliant with Waze's schema. The only automated way to use Esri's 2.0 solution and have a Waze Feed is to create another feature service with a schema that matches what Waze requires and then create a python script that translates the Esri data to the Waze schema. Then schedule the script to run at a specific interval.

I have not done this yet. Honestly, I have been putting it off hoping that Waze would become a partner with Esri's live feed. I still input the road closures into Esri's solution and then log into Waze's Partner Hub to add the same closures there.

"Not all those who wander are lost" ~ Tolkien
Jennifer_Parmeley
Frequent Contributor

I think "Work Area" one of my testing values - so my mistake on the post. 
It still doesn't make sense that Hazard doesn't work. 

0 Kudos
Joshua-Young
Honored Contributor

I found an archive of the version 1.0 schema of the Road Closure solution in my files and have attached a copy showing how the data schema used to be setup to support Waze Feeds. 

Waze is expecting a "type" field and a "subtype" field. The "type" field value for road closures is always ROAD_CLOSED, and the subtype field is going to be either ROAD_CLOSED_CONSTRUCTION, ROAD_CLOSED_EVENT, or ROAD_CLOSED_HAZARD. The values are all caps and underscores for spaces.

The version 2.0 of the Road Closure solution changed the "type" field to "reason", got rid of the subtype field, and changed the "reason" values to "Construction", "Event", or "Hazard". That is why Waze does not recognize the input anymore. If you want to use Esri and Waze while only editing one feature service, you will need a Python script that extracts, translates, and loads the data from the Esri format to the Waze format.

"Not all those who wander are lost" ~ Tolkien
Joshua-Young
Honored Contributor

@Jennifer_Parmeley this prompted me to finally work on a Python script to sync the v2.0 schema with the v1.0 schema. This may not be the most optimal way to do this, but here is the Python script we are now using. The script takes the v2.0 service and translates the data to match the v1.0 service. Then it compares the content of the v2.0 service to that of the v1.0 service to see if an update is needed. If the data matches the script exits, but if there is a difference then the v1.0 service is truncated and the new data is added.

For all of this to work the v1.0 service needs to have supportsApplyEditsWithGlobalIds set to True and Sync cannot be enabled on the service. The GlobalID setting is needed to copy the GlobalIDs from v2.0 to v1.0 otherwise new GlobalID are created. The GlobalIDs are needed for the comparison. Sync must be disabled or the truncate operation will fail.

I am running this on ArcGIS Enterprise using ArcGIS Notebook Server Standard, but it should work with ArcGIS Online and/or a standalone Python file running as a scheduled task with some adjustments to the code.

from arcgis.gis import GIS
from arcgis.features import GeoAccessor
import pandas as pd
import numpy as np

gis = GIS("home")

# Get the Esri road closures layer using its Item ID
item_esri_closures = gis.content.get('<InsertEsriItemIDHere>')

# Get just the closure lines layer from the Esri road closure item
layer_esri_closures = item_esri_closures.layers[1]

# Convert the feature layer to a spatial Pandas dataframe
sdf_esri = GeoAccessor.from_layer(layer_esri_closures)

# Create a column to store the Waze "type" value and default it to ROAD_CLOSED
sdf_esri['type'] = 'ROAD_CLOSED'

# Create a column to store the Waze "reference" value and default it to organization ID
sdf_esri['reference'] = '<InsertWazeOrganizationIDHere>'

# Replace the Esri "reason" values with the Waze equivalent
sdf_esri['reason'] = sdf_esri['reason'].replace({'Construction':'ROAD_CLOSURE_CONSTRUCTION', 'Event':'ROAD_CLOSURE_EVENT', 'Hazard':'ROAD_CLOSURE_HAZARD'})

# Replace the Esri "direction" values with the Waze equivalent
sdf_esri['direction'] = sdf_esri['direction'].replace({'Both Directions':'BOTH_DIRECTIONS','One Direction':'ONE_DIRECTION'})

# Rename Esri columns to match Waze column names
sdf_esri = sdf_esri.rename(columns={'reason':'subtype', 'closureid':'identifier'})

# Keep only the columns that match the Waze schema
sdf_esri = sdf_esri[['street','subtype','description','direction','altroute','pocname','pocemail',
                     'pocphone','url','identifier','activeincid','type','reference','globalid',
                     'created_user','last_edited_user','created_date','starttime','last_edited_date',
                     'endtime','SHAPE','SHAPE__Length','objectid']]

# Get the Waze road closure service using its item ID
item_waze_closures = gis.content.get('InsertWazeItemIDHere')

# Create a feature layer object of the closure lines layer from the Waze road closure item
layer_waze_closures = item_waze_closures.layers[0]

# Convert the feature layer to a spatial dataframe
sdf_waze = GeoAccessor.from_layer(layer_waze_closures)

# Compare just a subset of the fields from both services
# Apparently the SHAPE and SHAPE__Length are modified slightly when applying the edits
# so they will not match
compare_fields = ['street','subtype','description','direction','altroute','pocname','pocemail',
                     'pocphone','url','identifier','activeincid','type','reference','globalid',
                     'created_user','last_edited_user','created_date','starttime','last_edited_date',
                     'endtime']

sdf_waze_compare = sdf_waze[compare_fields]

sdf_esri_compare = sdf_esri[compare_fields]

# Make sure the null values are the same between the dataframes
sdf_waze_compare = sdf_waze_compare.replace(np.nan,'')
sdf_waze_compare = sdf_waze_compare.replace(np.nan,'')

# Make sure the dataframes are sorted the same way using the GlobalID
sdf_esri_sort = sdf_esri_compare.sort_values(by='globalid', ignore_index=True)
sdf_waze_sort = sdf_waze_compare.sort_values(by='globalid', ignore_index=True)

# Set the index of both dataframes to use the GlobalID
sdf_esri_sort = sdf_esri_sort.set_index('globalid')
sdf_waze_sort = sdf_waze_sort.set_index('globalid')

# Check if the number of rows are the same
equal_indexes = sdf_esri_sort.index.equals(sdf_waze_sort.index)
print('Row Count Equal:    ' + str(equal_indexes))

# Check if the number of columns are the same
equal_columns = sdf_esri_sort.columns.equals(sdf_waze_sort.columns)
print('Column Count Equal: ' + str(equal_columns))

# Check if the data in the dataframes already match
exists = sdf_esri_sort.isin(sdf_waze_sort.to_dict(orient='list')).all(axis=1)
equal_values = False
if all(exists):
    print('Data Equal:         True')
    equal_values = True
else:
    print('Data Equal:         False')
    equal_values = False

    # A list of the check values
checks = [equal_indexes,equal_columns,equal_values]

if all(checks):
    # If all the checks are True then everything is
    # exactly the same and nothing needs to be updated
    print('Nothing to update')
else:
    # If one of the checks is False then update the Waze service
    # Convert the translated dataframe of the Esri service to a FeatureSet
    featureset_esri = sdf_esri.spatial.to_featureset()
    
    # Remove all existing rows from the Waze feature layer
    layer_waze_closures.manager.truncate()
    
    # Add the road closures from the translated Esri dataframe to the Waze service
    # The supportsApplyEditsWithGlobalIds must be set to True on the Waze service
    # or the edit operation will fail
    layer_waze_closures.edit_features(adds=featureset_esri, use_global_ids=True)
    print('Updated Waze service')

 

"Not all those who wander are lost" ~ Tolkien
Jennifer_Parmeley
Frequent Contributor

First - this is awesome and you deserve some kudos and recognition for this work. Thank you!

Second - I apologize for the slow response. Ya know those weeks when everything happens at once? Yeah. 

After looking at this with a couple of other folks I reached out to Waze on their partner support forums and then put in a support ticket at their suggestion. They have agreed to accept the 3 ESRI values, in the ArcGIS RC Solution 2.0. I have not tested but should be able to submit 'Construction' 'Event' and 'Hazard' and they should populate to reason (ESRI) or type (Waze). 

What I've done to make this work for us.
> I customized the RC Solution hosted feature layer to meet the needs of our city.
> I cleaned up the view I'd messed with and submitted to ESRI and Waze. removing all my "extra" domain values and fields. This made ESRI happy and the view has been accepted to Community Maps.
> I published a second view (of the same Solution layer) to use in our road closure application. This one has all the fields we need/were using and some of the ESRI/Waze fields.   

This week will be testing, rebuilding my edit application (again), and implementation. There will be a small about of extra work for the folks that enter our data, but a few extra fields (with domains) should be manageable to make the folks asking for the push to Waze happy. In time we should be able to roll more of the city app towards the ESRI/Waze data, but I'm making small changes slowly in this age of social media warriors.    

0 Kudos