mirror of
https://github.com/ev-map/EVMap.git
synced 2026-04-23 15:47:08 -04:00
implement getChargepointRadius for Android Auto
This commit is contained in:
@@ -14,7 +14,7 @@ interface ChargepointApi<out T : ReferenceData> {
|
||||
referenceData: ReferenceData,
|
||||
bounds: LatLngBounds,
|
||||
zoom: Float,
|
||||
filters: FilterValues
|
||||
filters: FilterValues?
|
||||
): Resource<List<ChargepointListItem>>
|
||||
|
||||
suspend fun getChargepointsRadius(
|
||||
@@ -22,7 +22,7 @@ interface ChargepointApi<out T : ReferenceData> {
|
||||
location: LatLng,
|
||||
radius: Int,
|
||||
zoom: Float,
|
||||
filters: FilterValues
|
||||
filters: FilterValues?
|
||||
): Resource<List<ChargepointListItem>>
|
||||
|
||||
suspend fun getChargepointDetail(
|
||||
|
||||
@@ -132,42 +132,44 @@ class GoingElectricApiWrapper(
|
||||
referenceData: ReferenceData,
|
||||
bounds: LatLngBounds,
|
||||
zoom: Float,
|
||||
filters: FilterValues
|
||||
filters: FilterValues?
|
||||
): Resource<List<ChargepointListItem>> {
|
||||
val freecharging = filters.getBooleanValue("freecharging")!!
|
||||
val freeparking = filters.getBooleanValue("freeparking")!!
|
||||
val open247 = filters.getBooleanValue("open_247")!!
|
||||
val barrierfree = filters.getBooleanValue("barrierfree")!!
|
||||
val excludeFaults = filters.getBooleanValue("exclude_faults")!!
|
||||
val minPower = filters.getSliderValue("min_power")!!
|
||||
val minConnectors = filters.getSliderValue("min_connectors")!!
|
||||
val freecharging = filters?.getBooleanValue("freecharging")
|
||||
val freeparking = filters?.getBooleanValue("freeparking")
|
||||
val open247 = filters?.getBooleanValue("open_247")
|
||||
val barrierfree = filters?.getBooleanValue("barrierfree")
|
||||
val excludeFaults = filters?.getBooleanValue("exclude_faults")
|
||||
val minPower = filters?.getSliderValue("min_power")
|
||||
val minConnectors = filters?.getSliderValue("min_connectors")
|
||||
|
||||
val connectorsVal = filters.getMultipleChoiceValue("connectors")!!
|
||||
if (connectorsVal.values.isEmpty() && !connectorsVal.all) {
|
||||
// no connectors chosen
|
||||
return Resource.success(emptyList())
|
||||
val connectorsVal = filters?.getMultipleChoiceValue("connectors")
|
||||
if (connectorsVal != null) {
|
||||
if (connectorsVal.values.isEmpty() && !connectorsVal.all) {
|
||||
// no connectors chosen
|
||||
return Resource.success(emptyList())
|
||||
}
|
||||
connectorsVal.values = connectorsVal.values.mapNotNull {
|
||||
GEChargepoint.convertTypeToGE(it)
|
||||
}.toMutableSet()
|
||||
}
|
||||
connectorsVal.values = connectorsVal.values.mapNotNull {
|
||||
GEChargepoint.convertTypeToGE(it)
|
||||
}.toMutableSet()
|
||||
val connectors = formatMultipleChoice(connectorsVal)
|
||||
|
||||
val chargeCardsVal = filters.getMultipleChoiceValue("chargecards")!!
|
||||
if (chargeCardsVal.values.isEmpty() && !chargeCardsVal.all) {
|
||||
val chargeCardsVal = filters?.getMultipleChoiceValue("chargecards")
|
||||
if (chargeCardsVal != null && chargeCardsVal.values.isEmpty() && !chargeCardsVal.all) {
|
||||
// no chargeCards chosen
|
||||
return Resource.success(emptyList())
|
||||
}
|
||||
val chargeCards = formatMultipleChoice(chargeCardsVal)
|
||||
|
||||
val networksVal = filters.getMultipleChoiceValue("networks")!!
|
||||
if (networksVal.values.isEmpty() && !networksVal.all) {
|
||||
val networksVal = filters?.getMultipleChoiceValue("networks")
|
||||
if (networksVal != null && networksVal.values.isEmpty() && !networksVal.all) {
|
||||
// no networks chosen
|
||||
return Resource.success(emptyList())
|
||||
}
|
||||
val networks = formatMultipleChoice(networksVal)
|
||||
|
||||
val categoriesVal = filters.getMultipleChoiceValue("categories")!!
|
||||
if (categoriesVal.values.isEmpty() && !categoriesVal.all) {
|
||||
val categoriesVal = filters?.getMultipleChoiceValue("categories")
|
||||
if (categoriesVal != null && categoriesVal.values.isEmpty() && !categoriesVal.all) {
|
||||
// no categories chosen
|
||||
return Resource.success(emptyList())
|
||||
}
|
||||
@@ -175,7 +177,7 @@ class GoingElectricApiWrapper(
|
||||
|
||||
// do not use clustering if filters need to be applied locally.
|
||||
val useClustering = zoom < 13
|
||||
val geClusteringAvailable = minConnectors <= 1
|
||||
val geClusteringAvailable = minConnectors == null || minConnectors <= 1
|
||||
val useGeClustering = useClustering && geClusteringAvailable
|
||||
val clusterDistance = if (useClustering) getClusterDistance(zoom) else null
|
||||
|
||||
@@ -192,12 +194,12 @@ class GoingElectricApiWrapper(
|
||||
clustering = useGeClustering,
|
||||
zoom = zoom,
|
||||
clusterDistance = clusterDistance,
|
||||
freecharging = freecharging,
|
||||
minPower = minPower,
|
||||
freeparking = freeparking,
|
||||
open247 = open247,
|
||||
barrierfree = barrierfree,
|
||||
excludeFaults = excludeFaults,
|
||||
freecharging = freecharging ?: false,
|
||||
minPower = minPower ?: 0,
|
||||
freeparking = freeparking ?: false,
|
||||
open247 = open247 ?: false,
|
||||
barrierfree = barrierfree ?: false,
|
||||
excludeFaults = excludeFaults ?: false,
|
||||
plugs = connectors,
|
||||
chargecards = chargeCards,
|
||||
networks = networks,
|
||||
@@ -216,38 +218,136 @@ class GoingElectricApiWrapper(
|
||||
}
|
||||
} while (startkey != null && startkey < 10000)
|
||||
|
||||
var result = data.filter { it ->
|
||||
// apply filters which GoingElectric does not support natively
|
||||
if (it is GEChargeLocation) {
|
||||
it.chargepoints
|
||||
.filter { it.power >= minPower }
|
||||
.filter { if (!connectorsVal.all) it.type in connectorsVal.values else true }
|
||||
.sumOf { it.count } >= minConnectors
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}.map { it.convert(apikey) } // convert to common model
|
||||
if (!geClusteringAvailable && useClustering) {
|
||||
// apply local clustering if server side clustering is not available
|
||||
Dispatchers.IO.run {
|
||||
result = cluster(result, zoom, clusterDistance!!)
|
||||
}
|
||||
}
|
||||
var result = postprocessResult(data, minPower, connectorsVal, minConnectors, zoom)
|
||||
|
||||
return Resource.success(result)
|
||||
}
|
||||
|
||||
private fun formatMultipleChoice(connectorsVal: MultipleChoiceFilterValue) =
|
||||
if (connectorsVal.all) null else connectorsVal.values.joinToString(",")
|
||||
private fun formatMultipleChoice(value: MultipleChoiceFilterValue?) =
|
||||
if (value == null || value.all) null else value.values.joinToString(",")
|
||||
|
||||
override suspend fun getChargepointsRadius(
|
||||
referenceData: ReferenceData,
|
||||
location: LatLng,
|
||||
radius: Int,
|
||||
zoom: Float,
|
||||
filters: FilterValues
|
||||
filters: FilterValues?
|
||||
): Resource<List<ChargepointListItem>> {
|
||||
TODO("Not yet implemented")
|
||||
val freecharging = filters?.getBooleanValue("freecharging")
|
||||
val freeparking = filters?.getBooleanValue("freeparking")
|
||||
val open247 = filters?.getBooleanValue("open_247")
|
||||
val barrierfree = filters?.getBooleanValue("barrierfree")
|
||||
val excludeFaults = filters?.getBooleanValue("exclude_faults")
|
||||
val minPower = filters?.getSliderValue("min_power")
|
||||
val minConnectors = filters?.getSliderValue("min_connectors")
|
||||
|
||||
val connectorsVal = filters?.getMultipleChoiceValue("connectors")
|
||||
if (connectorsVal != null) {
|
||||
if (connectorsVal.values.isEmpty() && !connectorsVal.all) {
|
||||
// no connectors chosen
|
||||
return Resource.success(emptyList())
|
||||
}
|
||||
connectorsVal.values = connectorsVal.values.mapNotNull {
|
||||
GEChargepoint.convertTypeToGE(it)
|
||||
}.toMutableSet()
|
||||
}
|
||||
val connectors = formatMultipleChoice(connectorsVal)
|
||||
|
||||
val chargeCardsVal = filters?.getMultipleChoiceValue("chargecards")
|
||||
if (chargeCardsVal != null && chargeCardsVal.values.isEmpty() && !chargeCardsVal.all) {
|
||||
// no chargeCards chosen
|
||||
return Resource.success(emptyList())
|
||||
}
|
||||
val chargeCards = formatMultipleChoice(chargeCardsVal)
|
||||
|
||||
val networksVal = filters?.getMultipleChoiceValue("networks")
|
||||
if (networksVal != null && networksVal.values.isEmpty() && !networksVal.all) {
|
||||
// no networks chosen
|
||||
return Resource.success(emptyList())
|
||||
}
|
||||
val networks = formatMultipleChoice(networksVal)
|
||||
|
||||
val categoriesVal = filters?.getMultipleChoiceValue("categories")
|
||||
if (categoriesVal != null && categoriesVal.values.isEmpty() && !categoriesVal.all) {
|
||||
// no categories chosen
|
||||
return Resource.success(emptyList())
|
||||
}
|
||||
val categories = formatMultipleChoice(categoriesVal)
|
||||
|
||||
// do not use clustering if filters need to be applied locally.
|
||||
val useClustering = zoom < 13
|
||||
val geClusteringAvailable = minConnectors == null || minConnectors <= 1
|
||||
val useGeClustering = useClustering && geClusteringAvailable
|
||||
val clusterDistance = if (useClustering) getClusterDistance(zoom) else null
|
||||
|
||||
var startkey: Int? = null
|
||||
val data = mutableListOf<GEChargepointListItem>()
|
||||
do {
|
||||
// load all pages of the response
|
||||
try {
|
||||
val response = api.getChargepointsRadius(
|
||||
location.latitude, location.longitude, radius,
|
||||
clustering = useGeClustering,
|
||||
zoom = zoom,
|
||||
clusterDistance = clusterDistance,
|
||||
freecharging = freecharging ?: false,
|
||||
minPower = minPower ?: 0,
|
||||
freeparking = freeparking ?: false,
|
||||
open247 = open247 ?: false,
|
||||
barrierfree = barrierfree ?: false,
|
||||
excludeFaults = excludeFaults ?: false,
|
||||
plugs = connectors,
|
||||
chargecards = chargeCards,
|
||||
networks = networks,
|
||||
categories = categories,
|
||||
startkey = startkey
|
||||
)
|
||||
if (!response.isSuccessful || response.body()!!.status != "ok") {
|
||||
return Resource.error(response.message(), null)
|
||||
} else {
|
||||
val body = response.body()!!
|
||||
data.addAll(body.chargelocations)
|
||||
startkey = body.startkey
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
return Resource.error(e.message, null)
|
||||
}
|
||||
} while (startkey != null && startkey < 10000)
|
||||
|
||||
val result = postprocessResult(data, minPower, connectorsVal, minConnectors, zoom)
|
||||
return Resource.success(result)
|
||||
}
|
||||
|
||||
private fun postprocessResult(
|
||||
chargers: List<GEChargepointListItem>,
|
||||
minPower: Int?,
|
||||
connectorsVal: MultipleChoiceFilterValue?,
|
||||
minConnectors: Int?,
|
||||
zoom: Float
|
||||
): List<ChargepointListItem> {
|
||||
// apply filters which GoingElectric does not support natively
|
||||
var result = chargers.filter { it ->
|
||||
if (it is GEChargeLocation) {
|
||||
it.chargepoints
|
||||
.filter { it.power >= (minPower ?: 0) }
|
||||
.filter { if (connectorsVal != null && !connectorsVal.all) it.type in connectorsVal.values else true }
|
||||
.sumOf { it.count } >= (minConnectors ?: 0)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}.map { it.convert(apikey) }
|
||||
|
||||
// apply clustering
|
||||
val useClustering = zoom < 13
|
||||
val geClusteringAvailable = minConnectors == null || minConnectors <= 1
|
||||
val clusterDistance = if (useClustering) getClusterDistance(zoom) else null
|
||||
if (!geClusteringAvailable && useClustering) {
|
||||
// apply local clustering if server side clustering is not available
|
||||
Dispatchers.IO.run {
|
||||
result = cluster(result, zoom, clusterDistance!!)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override suspend fun getChargepointDetail(
|
||||
|
||||
@@ -33,6 +33,20 @@ interface OpenChargeMapApi {
|
||||
@Query("maxresults") maxresults: Int = 500,
|
||||
): Response<List<OCMChargepoint>>
|
||||
|
||||
@GET("poi/")
|
||||
suspend fun getChargepointsRadius(
|
||||
@Query("latitude") latitude: Double,
|
||||
@Query("longitude") longitude: Double,
|
||||
@Query("distance") distance: Double,
|
||||
@Query("distanceunit") distanceUnit: String = "KM",
|
||||
@Query("connectiontypeid") plugs: String? = null,
|
||||
@Query("minpowerkw") minPower: Double? = null,
|
||||
@Query("operatorid") operators: String? = null,
|
||||
@Query("compact") compact: Boolean = true,
|
||||
@Query("statustypeid") statusType: String? = null,
|
||||
@Query("maxresults") maxresults: Int = 500,
|
||||
): Response<List<OCMChargepoint>>
|
||||
|
||||
@GET("poi/")
|
||||
suspend fun getChargepointDetail(
|
||||
@Query("chargepointid") id: Long,
|
||||
@@ -91,8 +105,8 @@ class OpenChargeMapApiWrapper(
|
||||
|
||||
override fun getName() = "OpenChargeMap.org"
|
||||
|
||||
private fun formatMultipleChoice(value: MultipleChoiceFilterValue) =
|
||||
if (value.all) null else value.values.joinToString(",")
|
||||
private fun formatMultipleChoice(value: MultipleChoiceFilterValue?) =
|
||||
if (value == null || value.all) null else value.values.joinToString(",")
|
||||
|
||||
// Unknown, Currently Available, Currently In Use, Operational, Partly Operational
|
||||
private val noFaultStatuses = "0,10,20,50,75"
|
||||
@@ -101,23 +115,23 @@ class OpenChargeMapApiWrapper(
|
||||
referenceData: ReferenceData,
|
||||
bounds: LatLngBounds,
|
||||
zoom: Float,
|
||||
filters: FilterValues,
|
||||
filters: FilterValues?,
|
||||
): Resource<List<ChargepointListItem>> {
|
||||
val referenceData = referenceData as OCMReferenceData
|
||||
|
||||
val minPower = filters.getSliderValue("min_power")!!.toDouble()
|
||||
val minConnectors = filters.getSliderValue("min_connectors")!!
|
||||
val excludeFaults = filters.getBooleanValue("exclude_faults")!!
|
||||
val minPower = filters?.getSliderValue("min_power")?.toDouble()
|
||||
val minConnectors = filters?.getSliderValue("min_connectors")
|
||||
val excludeFaults = filters?.getBooleanValue("exclude_faults")
|
||||
|
||||
val connectorsVal = filters.getMultipleChoiceValue("connectors")!!
|
||||
if (connectorsVal.values.isEmpty() && !connectorsVal.all) {
|
||||
val connectorsVal = filters?.getMultipleChoiceValue("connectors")
|
||||
if (connectorsVal != null && connectorsVal.values.isEmpty() && !connectorsVal.all) {
|
||||
// no connectors chosen
|
||||
return Resource.success(emptyList())
|
||||
}
|
||||
val connectors = formatMultipleChoice(connectorsVal)
|
||||
|
||||
val operatorsVal = filters.getMultipleChoiceValue("operators")!!
|
||||
if (operatorsVal.values.isEmpty() && !operatorsVal.all) {
|
||||
val operatorsVal = filters?.getMultipleChoiceValue("operators")!!
|
||||
if (operatorsVal != null && operatorsVal.values.isEmpty() && !operatorsVal.all) {
|
||||
// no operators chosen
|
||||
return Resource.success(emptyList())
|
||||
}
|
||||
@@ -131,28 +145,20 @@ class OpenChargeMapApiWrapper(
|
||||
minPower = minPower,
|
||||
plugs = connectors,
|
||||
operators = operators,
|
||||
statusType = if (excludeFaults) noFaultStatuses else null
|
||||
statusType = if (excludeFaults == true) noFaultStatuses else null
|
||||
)
|
||||
if (!response.isSuccessful) {
|
||||
return Resource.error(response.message(), null)
|
||||
}
|
||||
|
||||
var result = response.body()!!.filter { it ->
|
||||
// apply filters which OCM does not support natively
|
||||
it.connections
|
||||
.filter { it.power == null || it.power >= minPower }
|
||||
.filter { if (!connectorsVal.all) it.connectionTypeId in connectorsVal.values.map { it.toLong() } else true }
|
||||
.sumOf { it.quantity ?: 0 } >= minConnectors
|
||||
}.map { it.convert(referenceData) }.distinct() as List<ChargepointListItem>
|
||||
|
||||
val useClustering = zoom < 13
|
||||
val clusterDistance = if (useClustering) getClusterDistance(zoom) else null
|
||||
if (useClustering) {
|
||||
Dispatchers.IO.run {
|
||||
result = cluster(result, zoom, clusterDistance!!)
|
||||
}
|
||||
}
|
||||
|
||||
var result = postprocessResult(
|
||||
response.body()!!,
|
||||
minPower,
|
||||
connectorsVal,
|
||||
minConnectors,
|
||||
referenceData,
|
||||
zoom
|
||||
)
|
||||
return Resource.success(result)
|
||||
}
|
||||
|
||||
@@ -161,9 +167,76 @@ class OpenChargeMapApiWrapper(
|
||||
location: LatLng,
|
||||
radius: Int,
|
||||
zoom: Float,
|
||||
filters: FilterValues
|
||||
filters: FilterValues?
|
||||
): Resource<List<ChargepointListItem>> {
|
||||
TODO("Not yet implemented")
|
||||
val referenceData = referenceData as OCMReferenceData
|
||||
|
||||
val minPower = filters?.getSliderValue("min_power")?.toDouble()
|
||||
val minConnectors = filters?.getSliderValue("min_connectors")
|
||||
val excludeFaults = filters?.getBooleanValue("exclude_faults")
|
||||
|
||||
val connectorsVal = filters?.getMultipleChoiceValue("connectors")
|
||||
if (connectorsVal != null && connectorsVal.values.isEmpty() && !connectorsVal.all) {
|
||||
// no connectors chosen
|
||||
return Resource.success(emptyList())
|
||||
}
|
||||
val connectors = formatMultipleChoice(connectorsVal)
|
||||
|
||||
val operatorsVal = filters?.getMultipleChoiceValue("operators")
|
||||
if (operatorsVal != null && operatorsVal.values.isEmpty() && !operatorsVal.all) {
|
||||
// no operators chosen
|
||||
return Resource.success(emptyList())
|
||||
}
|
||||
val operators = formatMultipleChoice(operatorsVal)
|
||||
|
||||
val response = api.getChargepointsRadius(
|
||||
location.latitude, location.longitude,
|
||||
radius.toDouble(),
|
||||
minPower = minPower,
|
||||
plugs = connectors,
|
||||
operators = operators,
|
||||
statusType = if (excludeFaults == true) noFaultStatuses else null
|
||||
)
|
||||
if (!response.isSuccessful) {
|
||||
return Resource.error(response.message(), null)
|
||||
}
|
||||
|
||||
val result = postprocessResult(
|
||||
response.body()!!,
|
||||
minPower,
|
||||
connectorsVal,
|
||||
minConnectors,
|
||||
referenceData,
|
||||
zoom
|
||||
)
|
||||
return Resource.success(result)
|
||||
}
|
||||
|
||||
private fun postprocessResult(
|
||||
chargers: List<OCMChargepoint>,
|
||||
minPower: Double?,
|
||||
connectorsVal: MultipleChoiceFilterValue?,
|
||||
minConnectors: Int?,
|
||||
referenceData: OCMReferenceData,
|
||||
zoom: Float
|
||||
): List<ChargepointListItem> {
|
||||
// apply filters which OCM does not support natively
|
||||
var result = chargers.filter { it ->
|
||||
it.connections
|
||||
.filter { it.power == null || it.power >= (minPower ?: 0.0) }
|
||||
.filter { if (connectorsVal != null && !connectorsVal.all) it.connectionTypeId in connectorsVal.values.map { it.toLong() } else true }
|
||||
.sumOf { it.quantity ?: 0 } >= (minConnectors ?: 0)
|
||||
}.map { it.convert(referenceData) }.distinct() as List<ChargepointListItem>
|
||||
|
||||
// apply clustering
|
||||
val useClustering = zoom < 13
|
||||
if (useClustering) {
|
||||
val clusterDistance = getClusterDistance(zoom)
|
||||
Dispatchers.IO.run {
|
||||
result = cluster(result, zoom, clusterDistance!!)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override suspend fun getChargepointDetail(
|
||||
|
||||
Reference in New Issue
Block a user