Documentation Index
Fetch the complete documentation index at: https://docs.axle.energy/llms.txt
Use this file to discover all available pages before exploring further.
Axle works with Enode to provide access to a wide array of EVs, chargers, heat pumps, and batteries.
Axle will call the Enode API directly on your behalf to read from and control assets. We provide a pre-built integration
to help you gather credentials from your users, access assets, and confer the ability to control them to Axle.
Enode host their own onboarding flow - LinkUI. This guide
will demonstrate how to use Axle Components and LinkUI to onboard and connect an asset.
If you’re developing in another platform, get in touch to discuss how we can provide a native integration.
Step 1: Render the Axle Enode component
This is a helper component, which will automatically generate and return correctly
scoped Enode tokens.
The end user will see a loading indicator, and you’ll need to listen to messages to correctly
show the Native Enode SDK.
import SwiftUI
import WebKit
struct WebView: UIViewRepresentable {
let url: String
func makeUIView(context: Context) -> WKWebView {
let webView = WKWebView()
return webView
}
func updateUIView(_ webView: WKWebView, context: Context) {
guard let url = URL(string: url) else { return }
let request = URLRequest(url: url)
webView.load(request)
}
}
struct AxleEnodeIntegration: View {
var body: some View {
NavigationView {
WebView(url: "https://app.axle.energy/form/enode/vehicle")
}
}
}
Step 2: Listen for the Enode token from the component
You’ll need to listen for the Enode token once the component has authenticated and fetched from Axle. The Enode
component automatically sends this token using WKWebView message handlers on iOS.
We’ll first register the message handlers in the WebView. This example is using SwiftUI,
but it’s also easy to do this in UIKit by implementing the WKScriptMessageHandler delegate.
Register message handler in the WebView
// In EnodeWebView struct
// Two way communication with parent view
@Binding var messageHandler: ((String, Any?) -> Void)?
func makeUIView(context: Context) -> WKWebView {
let webView = WKWebView()
// Register a message listener in the webview
let userContentController = webView.configuration.userContentController
userContentController.add(context.coordinator, name: "axleEnode")
return webView
}
// Called automatically by SwiftUI when instantiating the view
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, WKScriptMessageHandler {
var parent: WebView
init(_ parent: WebView) {
self.parent = parent
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
parent.messageHandler?(message.name, message.body)
}
}
struct AxleEnodeIntegration: View {
@State private var messageHandler: ((String, Any?) -> Void)?
var body: some View {
NavigationView {
WebView(url: "https://app.axle.energy/form/enode/vehicle", messageHandler: $messageHandler)
}
.onAppear {
setupMessageHandler()
}
}
private func setupMessageHandler() {
messageHandler = { messageName, messageBody in
DispatchQueue.main.async {
switch messageName {
case "axle:enode-handoff":
handleSuccess(data: messageBody)
default:
print("Unknown message: \(messageName)")
}
}
}
}
}
Step 3: Handle the Enode token and trigger LinkSDK
Once you receive the Enode token from the Axle component, you’ll need to present the LinkSDK to complete the asset connection. First, import LinkKit and add the necessary state variables.
Import LinkKit and add state variables
import SwiftUI
import LinkKit
struct AxleEnodeIntegration: View {
@State private var isLinkKitPresented = false
@State private var linkToken: String? = nil
@State private var messageHandler: ((String, Any?) -> Void)?
// ... rest of the view
}
Next, update your message handler to extract the link token from the response and trigger the LinkSDK:
Handle token and trigger LinkSDK
private func setupMessageHandler() {
messageHandler = { messageName, messageBody in
DispatchQueue.main.async {
switch messageName {
case "handoff":
// Extract link token from the response
if let responseData = messageBody as? [String: Any],
let token = responseData["linkToken"] as? String {
linkToken = token
isLinkKitPresented = true
}
default:
print("Unknown message: \(messageName)")
}
}
}
}
Finally, add the LinkKit sheet to your view and handle the results:
var body: some View {
NavigationView {
WebView(url: "https://app.axle.energy/form/enode/vehicle", messageHandler: $messageHandler)
}
.onAppear {
setupMessageHandler()
}
.linkKitSheet(isPresented: $isLinkKitPresented, linkToken: linkToken) { linkResult in
switch linkResult {
case .success(let success):
handleLinkSuccess(success)
case .failure(let error):
handleLinkError(error)
}
}
}
Add the success and error handlers:
private func handleLinkSuccess(_ success: LinkSuccessMetadata) {
print("LinkKit success: \(success)")
// Move to the next stage in your onboarding!
}
private func handleLinkError(_ error: LinkError) {
print("LinkKit error: \(error)")
// Handle LinkKit error
// Show error message to user or retry flow
}