oriceon/mammotion

Laravel client for the Mammotion Open API — control Luba / Yuka robot mowers: devices, live status, work parameters, commands and telemetry subscriptions.

Maintainers

Package info

github.com/oriceon/mammotion

pkg:composer/oriceon/mammotion

Transparency log

Statistics

Installs: 6

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.0 2026-08-03 11:23 UTC

This package is auto-updated.

Last update: 2026-08-03 11:25:06 UTC


README

Laravel client for the Mammotion Open API — list your Luba / Yuka robot mowers, read what they are doing right now, send work commands and subscribe to live telemetry.

use Oriceon\Mammotion\Facades\Mammotion;

$devices = Mammotion::devices();
$id      = $devices[0]['id'];

Mammotion::currentWork($id);      // status + battery + decoded job settings
Mammotion::start($id, 'Front yard');
Mammotion::pause($id);
Mammotion::returnToDock($id);

Requirements

Installation

composer require oriceon/mammotion

The service provider and the Mammotion alias are auto-discovered. Publish the config if you need to change it:

php artisan vendor:publish --tag=mammotion-config
php artisan vendor:publish --tag=mammotion-translations

Configuration

Only the credentials are mandatory:

MAMMOTION_CLIENT_ID=
MAMMOTION_CLIENT_SECRET=

Everything else has a sane default and can be overridden through config/mammotion.php or the environment:

Key Env Default Meaning
auth_url MAMMOTION_AUTH_URL https://id.mammotion.com OAuth2 server that issues the access token
api_url MAMMOTION_API_URL https://api-open.mammotion.com API server
language MAMMOTION_LANGUAGE en-US Sent as Accept-Language
timeout MAMMOTION_TIMEOUT 15 HTTP timeout, in seconds
token_leeway MAMMOTION_TOKEN_LEEWAY 60 Safety margin shaved off expires_in when caching the token
cache.store MAMMOTION_CACHE_STORE app default Cache store holding the tokens
cache.prefix MAMMOTION_CACHE_PREFIX mammotion Cache key prefix

Authentication

Authentication is client_credentials and is handled for you: every call fetches the token if needed, caches it until shortly before it expires (as Mammotion asks integrators to do) and, on a 401, re-authenticates and retries the request exactly once. A refresh_token, when the server returns one, is preferred over a new client_credentials exchange.

You never need to call it explicitly, but it is available:

Mammotion::accessToken();       // cached token
Mammotion::accessToken(true);   // force a new one
Mammotion::forgetToken();       // drop the cached tokens

Usage

Resolve the client however you prefer — facade, container, or a plain instance with explicit credentials:

use Oriceon\Mammotion\Facades\Mammotion;
use Oriceon\Mammotion\MammotionClient;

Mammotion::devices();
app(MammotionClient::class)->devices();
(new MammotionClient(clientId: '', clientSecret: ''))->devices();

Devices

Mammotion::devices();                 // every mower bound to the account
Mammotion::device('DEV-1');           // raw detail: status, battery, network, firmware
Mammotion::status('DEV-1');           // MammotionDeviceStatusEnum|null
Mammotion::isOnline('DEV-1');         // bool
Mammotion::batteryLevel('DEV-1');     // int|null

What the mower is doing right now

$snapshot = Mammotion::currentWork('DEV-1');
[
    'deviceId'          => 'DEV-1',
    'nickname'          => 'Yuka',
    'model'             => 'LUBA 3 AWD',
    'online'            => true,
    'status'            => MammotionDeviceStatusEnum::WORKING,
    'statusLabel'       => 'Working',
    'isWorking'         => true,
    'batteryLevel'      => 72,
    'isCharging'        => false,
    'job'               => MammotionJobContentEnum::MOWING_AND_COLLECTING,
    'jobLabel'          => 'Mowing and collecting',
    'settings'          => ['channelMode' => 'Cross stripes', 'knifeHeight' => '45 mm', …],
    'workParams'        => [ /* raw response */ ],
    'workParamsPending' => false,
    'network'           => ['usedNetwork' => '1', 'wifiRssi' => -46],
]

Two limitations belong to the Mammotion API, not to this package:

  1. REST does not expose which task or area is running, nor the progress percentage. Mammotion::tasks($id) only lists the tasks defined in the app, without marking the active one.
  2. work-params is asynchronous despite its name. The first GET merely asks the mower to report; the immediate response is often just {"commandResult": true, "resultMessage": "Command has been sent", …} with every value at 0.

The package never turns those zeros into settings. When it happens, settings stays empty and workParamsPending is true. To tell the two apart yourself:

$params = Mammotion::workParams('DEV-1');

Mammotion::workParamsArePopulated($params);   // false for an empty acknowledgement

// Ask a few times, in case the backend serves the mower's later report from cache:
Mammotion::workParamsPolled('DEV-1', attempts: 4, delayMs: 2000);

Live progress, track and coordinates arrive exclusively through the SSE push channel — see Telemetry.

Commands

Mammotion::start('DEV-1', 'Front yard');   // runs a task created in the Mammotion app
Mammotion::startImmediately('DEV-1');      // mow now, no plan
Mammotion::pause('DEV-1');
Mammotion::resume('DEV-1');
Mammotion::stop('DEV-1');                  // stops and cancels the task
Mammotion::returnToDock('DEV-1');
Mammotion::cancelReturn('DEV-1');

// Or the generic form:
Mammotion::action('DEV-1', MammotionActionEnum::START, 'Front yard');

Mammotion::taskNames('DEV-1') returns the names accepted by start().

Telemetry

Subscribing tells the Mammotion server to push updates over its SSE channel. A subscription expires after 10 minutes and has to be renewed; the API accepts at most 20 devices per request.

use Oriceon\Mammotion\Enums\MammotionSubscriptionPropertyEnum as Property;

Mammotion::subscribeDevice('DEV-1');   // basic telemetry set
Mammotion::subscribeDevice('DEV-1', [Property::WORK_PROGRESS, Property::COORDINATES]);

Mammotion::subscribe([
    'DEV-1' => [Property::DEVICE_STATUS, Property::BATTERY_PERCENT],
    'DEV-2' => Property::telemetry(),
]);

Enums

Enum Covers
MammotionActionEnum commands accepted by POST /v1/mower/action
MammotionDeviceStatusEnum mower states, mapped case-insensitively
MammotionJobContentEnum operating mode (mowing / collecting / both)
MammotionSubscriptionPropertyEnum telemetry property keys

Every case exposes a translated label(). Translations ship for en and ro; publish them to add your own locale.

Error handling

Both transport failures (HTTP != 2xx) and application errors (code other than 0 / 200 in the response envelope) raise MammotionApiException:

use Oriceon\Mammotion\Exceptions\MammotionApiException;

try {
    Mammotion::pause('DEV-1');
}
catch (MammotionApiException $e) {
    $e->getMessage();
    $e->apiCode;      // application code, e.g. 4001
    $e->httpStatus;   // HTTP status
    $e->requestId;    // Mammotion request id, useful for support
}

A missing or empty credential pair raises MammotionConfigurationException at build time.

Testing

The package is covered by Pest, and every HTTP call goes through Laravel's HTTP client — so Http::fake() is all you need in your own tests:

composer install
composer test

License

MIT. See LICENSE.md.