[Modul] Husqvarna Automower Connect

wissen tu ich das nicht.

Ich habe mal im Firefox Extra -> Web-Entwickler -> Web-Konsole aktiviert und bin auf den Reiter Netzwerkanalyse gegangen und dann die Grafik abgerufen.

Gesehen habe ich dann: maps.googleapis.com, maps.googleapis.com und fonts.googleapis.com.

Gruß
demel

Hallo Demel42,

erst mal: ein dickes Kompliment für das Projekt! Ich besitze seit 1 Woche einen Husqvarna Automower 315x und habe ihn auch gleich mit deinem Modul eingebunden. Vorher hatte ich einen Robomow RC312, der zwar das bessere Mähwerk und einen Kantenmodus hat, aber die Elektronik hinkt 10 Jahre hinterher.

Mich stört nur, dass Dein Modul erst ab IPS 5.3 installierbar ist, Ich tue mich mit dem Update etwas schwer, da IPS bei mir 3.2 GB groß ist und in meinem Augen nichts auf der System-Partition verloren hat. So habe ich nur Testweise ein Update gemacht möchte aber eigentlich auf IPS 5.2 bleiben.

Dann fiel mir beim Recherchieren auf, dass Husqvarna eine API bereitstellt, die auch halbwegs vernünftig dokumentiert ist:

https://developer.1689.cloud/apis

Nun meine Frage: benutzt Du tatsächlich IPS 5.3-spezifische Funktionen ? Beim überfliegen hatte ich zumindest nichts auf Anhieb entdeckt. Könntest Du also die Freigabe schon ab IPS 5.2 ändern ?

Oder noch besser: Könnten wir uns eventuell zusammen tun, auf die API mit Zugang unter :

https://api.amc.husqvarna.dev/v1

umstellen ? Vorteil wäre, dass mehr Funktionen verfügbar sind.

Anbei mal ein „wildes“ Test-Script zur Abfrage des Status und Senden von Befehlen:

<?

/*//////////////////////////////////////////////////////////////////////////////
Test Husqvarna API -Forum                                 2020 by André Liebmann
2020-04-29
--------------------------------------------------------------------------------
Links:				https://developer.1689.cloud/apis/Automower+Connect+API

API:					https://api.amc.husqvarna.dev/v1

Swagger:				https://developer.1689.cloud/apis/Automower+Connect+API#/swagger

Application key: 		XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

Application secret: 	        XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

/*//////////////////////////////////////////////////////////////////////////////

$Username			= "Mail-Adresse";

$Password			= "XXXX";

$Application_Key	        = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX";

$Application_Secret	= "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX";

$URl_Access			= "https://api.amc.husqvarna.dev/v1"; 

$URL_Token			= "https://api.authentication.husqvarnagroup.dev/v1/oauth2/token";

$Mower_ID			= "XXXXXXXXX-XXXXXXXX";
	
/*//////////////////////////////////////////////////////////////////////////////
function Automower_Get_Token($Application_Key, $Username, $Password, $URL_Token)
--------------------------------------------------------------------------------
CURL-Abfrage zur Ermittlung des Token
/*//////////////////////////////////////////////////////////////////////////////

function Automower_Get_Token($Application_Key, $Username, $Password, $URL_Token)
	{
	$curl = curl_init();
	
	$auth_data  = "grant_type=password&";
	$auth_data .= "client_id=".$Application_Key."&";
	$auth_data .= "username=".$Username."&";
	$auth_data .= "password=".$Password;
	
	curl_setopt($curl, CURLOPT_POST, 1);
	curl_setopt($curl, CURLOPT_POSTFIELDS, $auth_data);
	curl_setopt($curl, CURLOPT_URL, $URL_Token);
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
	
	$Result = curl_exec($curl);
	
	if(!$Result)
		{
		die("Connection Failure");
		}
	curl_close($curl);
	
	$ResultArray = json_decode($Result, true); //print_r($ResultArray);
	$Token       = $ResultArray["access_token"]; echo("
Token: $Token

");
	
	return $Token;
	}

$Token = Automower_Get_Token($Application_Key, $Username, $Password, $URL_Token);

/*//////////////////////////////////////////////////////////////////////////////
Alle Mower abfragen
/*//////////////////////////////////////////////////////////////////////////////

$URL = "https://api.amc.husqvarna.dev/v1/mowers";

if($Token)
	{	
	$curl = curl_init();
	
	curl_setopt($curl, CURLOPT_HTTPHEADER, array(
		"accept: application/vnd.api+json",
		"X-Api-Key: ".$Application_Key,
		"Authorization: Bearer ".$Token,
		"Authorization-Provider: husqvarna",
		));
	
	curl_setopt($curl, CURLOPT_URL, $URL);
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
	
	$Result = curl_exec($curl);
	
	if(!$Result)
		{
		die("Connection Failure 2");
		}
	
	curl_close($curl);
	
	$ResultArray = json_decode($Result, true); //print_r($ResultArray);
	}

/*//////////////////////////////////////////////////////////////////////////////
Ersten Mower abfragen
/*//////////////////////////////////////////////////////////////////////////////

$Mower_ID = $ResultArray["data"][0]["id"]; //echo($Mower_ID);

$URL = "https://api.amc.husqvarna.dev/v1/mowers/".$Mower_ID;

if($Token)
	{	
	$curl = curl_init();
	
	curl_setopt($curl, CURLOPT_HTTPHEADER, array(
		"accept: application/vnd.api+json",
		"X-Api-Key: ".$Application_Key,
		"Authorization: Bearer ".$Token,
		"Authorization-Provider: husqvarna",
		));
	
	curl_setopt($curl, CURLOPT_URL, $URL);
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
	
	$Result = curl_exec($curl);
	
	if(!$Result)
		{
		die("Connection Failure 2");
		}
	
	curl_close($curl);
	
	$ResultArray = json_decode($Result, true); //print_r($ResultArray);
	}

//echo(Automower_Request($Mower_ID, $Application_Key, $Token, $Method, $Action, $Attributes));

/*//////////////////////////////////////////////////////////////////////////////
function Automower_Send_Action

JSON-Strukturen:

Pause mower:

    data: {
      type: 'Pause'
    }

Park mower until next scheduled run:

    data: {
      type: 'ParkUntilNextSchedule'
    }

Park mower until further notice, overriding schedule:

    data: {
      type: 'ParkUntilFurtherNotice'
    }
	
Park mower for a duration of time, overriding schedule:

    data: {
      type: 'Park',
      attributes: {
        duration: 24
      }
    }

Resume mower according to schedule:

    data: {
      type: 'ResumeSchedule'
    }

Start mower and cut for a duration of time, overriding schedule:
	
    data: {
      type: 'Start',
      attributes: {
        duration: 24
      }
    }
	
/*//////////////////////////////////////////////////////////////////////////////

// Husqvarna API - URL
$URL = "https://api.amc.husqvarna.dev/v1/mowers/".$Mower_ID."/actions";
$Action = "Start";
$Attributes = '"attributes": { "duration":10 }';
$Message = '
		{
		"data": {
			"type":  "'.$Action.'",
			'.$Attributes.'
			}
		}
	';
$Method = "POST";

echo(Automower_Request($URL, $Mower_ID, $Application_Key, $Token, $Method, $Message));

function Automower_Request($URL, $Mower_ID, $Application_Key, $Token, $Method, $Message)
	{
	
	$URL = "https://api.amc.husqvarna.dev/v1/mowers/".$Mower_ID."/actions";
	
	// prepare CURL
	$curl = curl_init();
	
	curl_setopt($curl, CURLOPT_HTTPHEADER, array(
			"Accept: */*",
			"Content-Type: application/vnd.api+json",
			"X-Api-Key: ".$Application_Key,
			"Authorization: Bearer ".$Token,
			"Authorization-Provider: husqvarna",
			));
	
	curl_setopt($curl, CURLOPT_URL, $URL);
	
	curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $Method); 
	
	// set POSTFIELDS for "POST"
	if($Method == "POST")
		{
		curl_setopt($curl, CURLOPT_POSTFIELDS, $Message); 
		}                          
		
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
	
	$Result = curl_exec($curl); print_r($Result);
	
	curl_close($curl);
	
	// proof response
	if(preg_match("/errors/i", $Result))
		{
		$Detail = json_decode($Result, true);
		print_r($Detail);
		$Notification = 'ERROR: '.$Detail["errors"][0]["title"].' | '.$Detail["errors"][0]["detail"];
		}
	else
		{
		$Notification = "OK";
		} 
	
	// return response
	return $Notification;
	}

Sowie Status- und Error-Arrays:

<?php

/*//////////////////////////////////////////////////////////////////////////////
Husqvarna States and Errors                               2020 by André Liebmann
2020-04-29
/*//////////////////////////////////////////////////////////////////////////////

$Mode = array(
	'MAIN_AREA' 				=> 'Mower will mow until low battery. Go home and charge. Leave and continue mowing. Week schedule is used. Schedule can be overridden with forced park or forced mowing.',
	'DEMO'					=> 'Same as main area, but shorter times. No blade operation. ',
	'SECONDARY_AREA'		=> 'Mower is in secondary area. Schedule is overridden with forced park or forced mowing. Mower will mow for request time or untill the battery runs out. ',
	'HOME'					=> 'Mower goes home and parks forever. Week schedule is not used. Cannot be overridden with forced mowing. ',
	'UNKNOWN'				=> 'Unknown mode',
	);

$Activity = array(
	'UNKNOWN'				=> 'Unknown activity. ',
	'NOT_APPLICABLE'		=> 'Manual start required in mower. ',
	'MOWING'				=> 'Mower is mowing lawn. If in demo mode the blades are not in operation. ',
	'GOING_HOME'			=> 'Mower is going home to the charging station. ',
	'CHARGING'				=> 'Mower is charging in station due to low battery. ',
	'LEAVING' 				=> 'Mower is leaving the charging station. ',
	'PARKED_IN_CS' 			=> 'Mower is parked in charging station. ',
	'STOPPED_IN_GARDEN' 	=> 'Mower has stopped. Needs manual action to resume. ',
	);

$State = array(
	'UNKNOWN'				=> 'Unknown state. ',
	'NOT_APPLICABLE'		=> '',
	'PAUSED'				=> 'Mower has been paused by user. ',
	'IN_OPERATION'			=> 'See value in activity for status. ',
	'WAIT_UPDATING'			=> 'Mower is downloading new firmware. ',
	'WAIT_POWER_UP'		=> 'Mower is performing power up tests. ',
	'RESTRICTED'			=> 'Mower can currently not mow due to week calender, or override park. ',
	'OFF'					=> 'Mower is turned off. ',
	'STOPPED'				=> 'Mower is stopped requires manual action. ',
	'ERROR'					=> 'An error has occurred. Check errorCode. Mower requires manual action. ',
	'FATAL_ERROR'			=> 'An error has occurred. Check errorCode. Mower requires manual action. ',
	'ERROR_AT_POWER_UP'	=> 'An error has occurred. Check errorCode. Mower requires manual action. ',
	);

$Error_Codes = array(
	'0'  => 'Unexpected error',
	'1'  => 'Outside working area',
	'2'  => 'No loop signal',
	'3'  => 'Wrong loop signal',
	'4'  => 'Loop sensor problem, front',
	'5'  => 'Loop sensor problem, rear',
	'6'  => 'Loop sensor problem, left',
	'7'  => 'Loop sensor problem, right',
	'8'  => 'Wrong PIN code',
	'9'  => 'Trapped',
	'10' => 'Upside down',
	'11' => 'Low battery',
	'12' => 'Empty battery',
	'13' => 'No drive',
	'14' => 'Mower lifted',
	'15' => 'Lifted',
	'16' => 'Stuck in charging station',
	'17' => 'Charging station blocked',
	'18' => 'Collision sensor problem, rear',
	'19' => 'Collision sensor problem, front',
	'20' => 'Wheel motor blocked, right',
	'21' => 'Wheel motor blocked, left',
	'22' => 'Wheel drive problem, right',
	'23' => 'Wheel drive problem, left',
	'24' => 'Cutting system blocked',
	'25' => 'Cutting system blocked',
	'26' => 'Invalid sub-device combination',
	'27' => 'Settings restored',
	'28' => 'Memory circuit problem',
	'29' => 'Slope too steep',
	'30' => 'Charging system problem',
	'31' => 'STOP button problem',
	'32' => 'Tilt sensor problem',
	'33' => 'Mower tilted',
	'34' => 'Cutting stopped - slope too steep',
	'35' => 'Wheel motor overloaded, right',
	'36' => 'Wheel motor overloaded, left',
	'37' => 'Charging current too high',
	'38' => 'Electronic problem',
	'39' => 'Cutting motor problem',
	'40' => 'Limited cutting height range',
	'41' => 'Unexpected cutting height adj',
	'42' => 'Limited cutting height range',
	'43' => 'Cutting height problem, drive',
	'44' => 'Cutting height problem, curr',
	'45' => 'Cutting height problem, dir',
	'46' => 'Cutting height blocked',
	'47' => 'Cutting height problem',
	'48' => 'No response from charger',
	'49' => 'Ultrasonic problem',
	'50' => 'Guide 1 not found',
	'51' => 'Guide 2 not found',
	'52' => 'Guide 3 not found',
	'53' => 'GPS navigation problem',
	'54' => 'Weak GPS signal',
	'55' => 'Difficult finding home',
	'56' => 'Guide calibration accomplished',
	'57' => 'Guide calibration failed',
	'58' => 'Temporary battery problem',
	'59' => 'Temporary battery problem',
	'60' => 'Temporary battery problem',
	'61' => 'Temporary battery problem',
	'62' => 'Temporary battery problem',
	'63' => 'Temporary battery problem',
	'64' => 'Temporary battery problem',
	'65' => 'Temporary battery problem',
	'66' => 'Battery problem',
	'67' => 'Battery problem',
	'68' => 'Temporary battery problem',
	'69' => 'Alarm! Mower switched off',
	'70' => 'Alarm! Mower stopped',
	'71' => 'Alarm! Mower lifted',
	'72' => 'Alarm! Mower tilted',
	'73' => 'Alarm! Mower in motion',
	'74' => 'Alarm! Outside geofence',
	'75' => 'Connection changed',
	'76' => 'Connection NOT changed',
	'77' => 'Com board not available',
	'78' => 'Slipped - Mower has Slipped.Situation not solved with moving pattern',
	'79' => 'Invalid battery combination - Invalid combination of different battery types.',
	'80' => 'Cutting system imbalance Warning',
	'81' => 'Safety function faulty',
	'82' => 'Wheel motor blocked, rear right',
	'83' => 'Wheel motor blocked, rear left',
	'84' => 'Wheel drive problem, rear right',
	'85' => 'Wheel drive problem, rear left',
	'86' => 'Wheel motor overloaded, rear right',
	'87' => 'Wheel motor overloaded, rear left',
	'88' => 'Angular sensor problem',
	'89' => 'Invalid system configuration',
	'90' => 'No power in charging station',
	);

?>

Wenn ich die Struktur Deiner Scripte sehe bist Du mir da allerdings Meilenweit voraus. Mit Modulen habe ich Null-Erfahrung :rolleyes:

Besten Gruß

André

PS: gern auch über PN

Hmm, ganz kann ich das nicht mehr sagen, warum ich auf 5.3 gegangen bin. Ich habe auch kein 5.2 Testsystem mehr, daher kann ich das auch nicht so einfach testen. Hmm… Wenn ich tippen würde, wäre das der Konfigurator in AutomowerConfig und da das Element ‚info‘.

Grundsätzlich würde ich aber davon abraten, auf älteren Versionen „kleben“ zu bleiben.

Ja, die Frage ist schon gekommen und folgendes hatte ich dazu gesagt

ja, ich werde den OAuth-Zugang implementieren, im Winter habe ich es mangels Testmöglichkeit nicht gemacht und die letzten Wochen hatte ich keinen Kopf dafür, da war zu viel anderes zu regeln.
Aber es kommt!

Nur: das ist keine Ablösung der alten API, es fehlt etwas ganz wesentlichen in der API: die GPS-Positionen. Den Nutzern des Moduls, mit denen ich zu tun hatte, war das immer wichtig. Zwei Anfragen an den dort angegebenen Support wurde noch nicht einmal quittiert, geschweige denn beantwortet.

Also muss ein ein Zwitter werden, mit der neuen API, die (neben OAuth) etwas mehr Funktionen hat) und zusätzlich der Abruf nach der alten API, damit die GPS-Daten noch abgerufen werden.

Gruß
demel

@demel42

… ist was dran.

Gruß André

Hallo demel42,

die Parkfunktion setzt leider den Timer außer Kraft. Wie hast Du die Befehle herausbekommen? Gibt es da noch andere ?
Werde mich mal weiter mit der neuen API beschäftigen, da es da auch ohne Timerabschltung gehen sollte. Aber jedenfalls hast recht: es sollte ein Zwitter werden. Die GPS Daten machen das Ganze ja erst interessant.

VG André

Im Internet gesucht und andere Implementierungen gefunden. Ich vermute, das ich die Links im README aufgeführt habe.

Frage: wie kommst du denn an die neue API? Die setzt doch OAuth voraus, was paresy zwar eingerichtet hat, was aber noch nicht funktioniert (hatte ich paresy am Freitag geschrieben).

gruß
demle

Hallo demel42,

man muss eine App bei Husqvarna Developer registrieren und erhält einen Application-Key. Dann weiter mit CURL wie in meinem Test-Script, also ohne IPS.

VG André

PS: die Links stehen oben im Script. Registrieren muss man sich natürlich noch.

mal schauen, ob paresy sich demnächst meldet, sonst mache ich beide Anmeldungen.
das mit den „Developer-Keys“ habe ich in diversen Modulen gemacht, hat nur den Nachteil, das sich jeder User selbst einen solche Key holen muss. Mit OAuth entfällt das.

mal schauen
demel

Moin,
ich hätte hier bei einem Kunden einen Husqvarna 315X.
Bringe ich den ins Symcon? Braucht er zusätzliche Teile? Wenn ja, welche?
Mein erster „Mähauftrag“ - einmal musste das ja kommen … :smiley:

Grüße, Uwe

Hallo,

nein, zusätzlich Teile braucht er nicht, wenn der so ein „Autonomer Connect“-Modul im Mäher eigebaut ist, was die „X“-Modelle m.E. nach haben.

Der Anwender muss das in der Husqvarna-Cloud anmelden (das macht er mit der App von Husqvarna).
Dann wird den AutomowerConnect-Konfigurator installieren, einrichten und damit dann den/die Mäher anlegen.

Wenn man die Karte haben möchte, muss man die Position-Variablen archivieren. Dann braucht man dazu das GoogleMaps-Modul um damit die Karte zu zeichnen. Beispiel.Scripte sind im GoogleMaps-Modul, sonst melde Dich nochmal.

Der Zugang über OAuth mit der offiziellen API ist noch nicht spruchreif, das gibt es noch was zu klären, was die Limitierung des API-Abrufs angeht - die ist absurd niedrig angesetzt. Ich hatte paresy gebeten, da man bei Husqvarna nachzuhaken - wenn das Ergebnis brauchbar ist, gehts weiter.
Leider ist es so, das die alte „inoffizielle“ API nicht alle Steuerfunktionen bietet, die neue API bietet eine besser Störung (fast alles, was die APP auch kann), dafür gibt die keine Positionsdaten aus.

Also wird das aktualisierte Modul ein Mischmasch aus alter und offizieller API werden - ich war schon fast fertig, als ich auf die Limitierungen gestossen bin :mad:

Gruß
demel

Mäh, das war ja einfach :loveips:
Tolle Geschichte, wir konnten Herbie direkt mal los schicken … :smiley:
Das Google-Maps-Modul habe ich dann „auf die Schnelle“ nicht gefunden … wir haben das mal auf ‚Finetuning‘ verschoben.
Geht das auch so einfach wie der Mäher? :cool:

Vielleicht kannst du mir ja auch noch mit einem 2-Zeiler helfen: was muss ich denn für Komandos schicken um die Mähmaschine bei Regen (vom LCN ausgewertet) nach Hause zu schicken und anschliessend wieder in sein „Standardprogramm“?

Dicken Dank für die schnelle Antwort.
Grüße, Uwe

Das Modul heisst GoogleMaps. Ist natürlich nicht gahh so plug-und-play wie der Automower-Anschluss

  • man muss bei Google einen Account einrichten, der Abruf con Maps ist grundsätzlich kostenpflichtig , aber die Freigrenzen sind so hoch, das man da als Privatmann nicht dran kommt (steht alles in der Modul-Doku)
  • für die Anzeige braucht man - je nach gewünschter Art der Map - entweder ein Script jnd eine HTmL-Box oder alternativ ein WebHook, ein Script (des Webhook) und natürlich eine HTML-Box, wo der WebHook aufgerufen wirs.

Vielleicht kannst du mir ja auch noch mit einem 2-Zeiler helfen: was muss ich denn für Komandos schicken um die Mähmaschine bei Regen (vom LCN ausgewertet) nach Hause zu schicken und anschliessend wieder in sein „Standardprogramm“?

Die Befehle stehen in dem README, wäre hier ein AutomowerDevice_ParkMower().
Ob allerdings das Parken bewirkt, das der wieder im Standardprogramm weitermacht weis ich nicht, weil ich die zwar mal kmplementiert hatte, aber nicht nutze.
Den komplette Befehlssatz gibt es mit der neuen API, aber das dauert noch etwas

gruß
demel

Hallo demel,

ich wollte heute Dein Modul (Version 1.17 über Modulstore) ausprobieren. Ich habe einen Automower 450X, bringe es aber nicht ans laufen.

Die Anmeldung klappt und ein Automower wird ausgelesen, er kann aber nicht angelegt werden, weil das Modell „null“ ist.

Der HTTP Call (Debug Log) gibt folgendes zurück:

[
  {
    "id": "<Serial omitted>",
    "name": "Automower",
    "model": null,
    "swPackageVersionString": null,
    "valueFound": true,
    "status":
    {
      "batteryPercent": 100,
      "connected": true,
      "lastErrorCode": 0,
      "lastErrorCodeTimestamp": 0,
      "mowerStatus": "PARKED_TIMER",
      "nextStartSource": "WEEK_TIMER",
      "nextStartTimestamp": 1618999200,
      "operatingMode": "AUTO",
      "storedTimestamp": 1618930996725,
      "showAsDisconnected": false,
      "valueFound": true
    }
  }
]

Sieht alles ganz gut aus bis auf model und swPackageVersionString.

Wenn ich Deinen Code richtig interpretiere, dann verwendest Du das Modell eigentlich nur, um zu prüfen, ob GPS unterstützt wird. (Model „G“ oder „H“).

Irgendeine Idee wie ich das ans Laufen bekommen könnte?

VG
Bernd

Hallo demel,

bekomme ich Dein Modul auch mit einen Husqvarna 550 EPOS Automower verbunden?

Tom

Hallo,

ja, das mit dem GPS war auch ziemlich geraten. Da kann man sicher was machen. Was passiert denn genau, rumst es?

gruß
demel

Hallo,
kann ich nicht sagen. Hast Du denn versucht, es anzulegen?
ich würde erwarten, das alle Modelle funktionieren, die mit der Automower-App zu bedienen sind.

demel

Hier steht erst eine Kaufentscheidung an und ich möchte den gern in IPS haben. In den Beschreibungen ist immer eine andere App erwähnt. Wie könnte man herausbekommen ob er geht?

Tom

da kann ich leider nicht helfen. wie gesagt, ich nehme ja, das die Geräte, die über die Automower-App gesteuert werden kann, auch über die API angesteuert werden können
demel

Beim Versuch, die Instanz über den Konfigurator zu erzeugen, knallt es, vermutlich, weil das Model NULL ist. Jetzt habe ich testweise versucht, die Automower Instanz direkt anzulegen, das geht erfreulicherweise. Er bekommt auch Infos vom Mäher. Für mich passt das also soweit, falls Du dennoch weiter in die Analyse gehen willst, sag Bescheid…

VG
Bernd