[OBSOLETE] BMW ConnectedDrive

Hi all,

I’ve spent a bit of time today on this, as I have a BMW i3 but charge it away from home (round the corner from where I live). I wanted to integrate this into WebCoRE so that when the car was reaching a certain charge level I would get a notification through Alexa to let me know.

I’ve altered the DTH to include the stateofChargeHV variable which reports the battery level as a % (customised DTH below).

Now the DTH reports the charge level as an integer, therefore opening up the possibility to conduct an action based on this value.

I hope this is useful for some of you.

Best wishes,
Guy

/**
 *  BMW ConnectedDrive Car
 *
 *  Copyright 2018 Tom Beech
 *
 */
 
metadata {
	definition (name: "BMW ConnectedDrive Car", namespace: "ibeech", author: "ibeech") {
		capability "Lock"
    capability "Image Capture"
    capability "Refresh"
    capability "Polling"
    capability "Thermostat Fan Mode"
    capability "Light"
    
    attribute "Battery","number"
    
    command "startVentalation"
    command "flashLights"
   
	}

	simulator {
		// TODO: define status and reply messages here
	}

	tiles(scale: 2) {
    
	tiles {

        carouselTile("carImage", "device.image", action: "Image Capture.take", width: 3, height: 2) { }
			     
       	valueTile("carDetails", "device.carDetails", width: 3, height: 2) {
    		  state "val", label:'${currentValue}', defaultState: true
		}
        
        valueTile("Battery", "device.Battery", width: 3, height: 2) {
    		  state "val", label:'${currentValue}', defaultState: true
		}
        
        valueTile("carService", "device.carService", width: 6, height: 2) {
    		  state "val", label:'${currentValue}', defaultState: true
		}
        
        standardTile("lockCar", "lock", width: 2, height: 2) {
				state "default", label:'Lock', action:"lock", icon:"st.Home.home3", backgroundColor:"#79b821"
			}
        
        standardTile("unlockCar", "unlock", width: 2, height: 2) {
				state "default", label:'Unlock', action:"unlock", icon:"st.Home.home3", backgroundColor:"#79b821"
			}
        
        standardTile("flashLightButton", "flashLights", width: 2, height: 2) {
				state "default", label:'Flash', action:"flashLights", icon:"st.Lighting.light11", backgroundColor:"#79b821"
			}      
        
        standardTile("startVentalationButton", "startVentalation", width: 2, height: 2) {
				state "default", label:'Ventilate', action:"startVentalation", icon:"st.Home.home1", backgroundColor:"#79b821"
			}            
                        
    	standardTile("refresh", "refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
				state("default", label:'refresh', action:"refresh", icon:"st.secondary.refresh-icon")
			}

        main "startVentalationButton"
        details([ "carImage", "carDetails", "carService", "lockCar", "unlockCar", "flashLightButton", "startVentalationButton", "refresh"])
    }        
}
}

def refresh() {

	def serviceInfo = parent.getCarServicenfo(device.deviceNetworkId)
    
def string = device.displayName;
string += "\r\rMiles: ${serviceInfo.attributesMap.mileage} " 
string += "Charge: ${serviceInfo.attributesMap.chargingLevelHv} %" 
	sendEvent(name: "carDetails", value: string);
   
   	def integer = device.displayName;
integer = "${serviceInfo.attributesMap.chargingLevelHv}"
sendEvent(name: "Battery", value: integer);

string = "Location: ${getCarLocation(serviceInfo.attributesMap.gps_lat, serviceInfo.attributesMap.gps_lng)}"
serviceInfo.vehicleMessages.cbsMessages.each{msg -> 
    def info1 = formatServiceInfo(msg);
    if(info1 != "") string += "\r\n${info1}";
}
sendEvent(name: "carService", value: string);    
captureCarImage()
}

def getCarLocation(lat, lon) {

	def params = [
		uri: "https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lon}&key=AIzaSyD-nz_0qxBlvGj0WZjpbHfnA-rQG4anMtM"
	]	
log.debug params

httpGet(params) {response ->    
    log.debug "${response.data}"
    
		return response.data.results.formatted_address[0]
	}
}

def formatServiceInfo(msg){
	              
	if(msg == null) return "";

if(msg.unitOfLengthRemaining != "") {
	return "${msg.text}: ${msg.status}. Due ${msg.date} or ${msg.unitOfLengthRemaining}"
    } else {
    	return "${msg.text}: ${msg.status}. Due ${msg.date}"
}
}

def poll() {
	refresh()
checkStatus()
}

def lock() {
	log.debug "Locking"
parent.lockDoors(device.deviceNetworkId)
}

def unlock() {
	log.debug "Unlocking"
parent.unlockDoors(device.deviceNetworkId)
}

def startVentalation() {
	log.debug "Starting Ventilation"
parent.ventilate(device.deviceNetworkId)
}

def fanOn() {
	log.debug "fanOn hit"
	startVentalation();
}
def fanCirculate() {
	log.debug "fanCirculate hit"
	startVentalation();
}
def fanAuto() {
	log.debug "fanAuto hit"
	startVentalation();
}

def flashLights() {
	log.debug "Flashing lights ${device.deviceNetworkId}"
parent.flashLights(device.deviceNetworkId)
}
def on() {
	log.debug "Light.on hit"
flashLights()    
}
def off() {
	log.debug "Light.off hit. Unable to turn lights off as they only flash"
}

def getImageName() {
return java.util.UUID.randomUUID().toString().replaceAll('-','')
}

def captureCarImage() {
if(state.PicTaken) {
	// Pic was already taken, all done.    
} else {
    log.debug "Aquring image of car"
    def params = [
        uri: parent.getCarImageUrl(device.deviceNetworkId)
    ]

    try {
        httpGet(params) { response ->
            // we expect a content type of "image/jpeg" from the third party in this case
            if (response.status == 200 && response.headers.'Content-Type'.contains("image/png")) {
                def imageBytes = response.data
                if (imageBytes) {
                    def name = getImageName()
                    try {
                        storeImage(name, imageBytes)
                        state.PicTaken = true
                    } catch (e) {
                        log.error "Error storing image ${name}: ${e}"
                    }

                }
            } else {
                log.error "Image response not successful or not a jpeg response"
            }
        }
    } catch (err) {
        log.debug "Error making request: $err"
    }
}
}

// parse events into attributes
def parse(String description) {
	log.debug "Virtual siwtch parsing '${description}'"
}