MockScale never emits again after a disconnect, blocking auxiliary-scale testing

Open Beginner friendly
#900 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
84/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active

Research direction

Start with lib/src/models/device/impl/mock_scale/mock_scale.dart, focusing on simulateDisconnect(), onConnect(), and _startEmission(). Compare the reconnect behavior with MockBengle and MockDe1, then verify that disconnecting and reconnecting MockScale produces subsequent snapshot frames on /ws/v1/scales/MockScale/snapshot.

Written by the indexing model from the issue text.

Description

Summary

MockScale stops emitting snapshots the first time it is disconnected and never starts again for the life of the process. Anything that needs a simulated scale to be disconnected and reconnected — the auxiliary scale role most of all — cannot be exercised end to end.

Why

lib/src/models/device/impl/mock_scale/mock_scale.dart

@override
disconnect() async {
  simulateDisconnect();
}

void simulateDisconnect() {
  _stalled = true;
  _emissionTimer?.cancel();
  _emissionTimer = null;
  detachMachine();
  _connectionSubject.add(ConnectionState.disconnected);
}

_startEmission() is called only from the constructor. onConnect() adds ConnectionState.connected and nothing else — it does not clear _stalled and does not restart the timer:

@override
Future<void> onConnect() async {
  _connectionSubject.add(ConnectionState.connected);
}

So after one disconnect() the scale reports itself connected again, the registry opens a session, /ws/v1/scales/MockScale/snapshot sends {"status":"connected"} — and no weight ever follows.

How it showed up

Verifying that a skin's dosing-scale feature works against the auxiliary role on 0.8.7-beta.1. The control plane is all correct:

  • GET /api/v1/devices reports connectionRole, and the connected primary is correctly excluded from what a skin may offer as a second scale
  • PUT /api/v1/devices/connect {connectionRole: "auxiliary"} after releasing it: role comes back auxiliary
  • PUT /api/v1/scales/MockScale/tare on the auxiliary session: 200
  • preferredScaleId is untouched throughout, as the contract requires
  • asking for auxiliary while it is still claimed as primary: 409 conflict

The data plane could not be checked at all:

ws://.../ws/v1/scales/MockScale/snapshot
[1] {"status":"connected"}
4 seconds, 1 frame total

MockScale emits every 200 ms from a broadcast controller, and _Session.start() subscribes to scale.currentSnapshot correctly, so nothing in the registry or the handler is at fault — the source had simply been switched off by the earlier disconnect.

There is no way around it on a simulated setup: the scale auto-connects as primary at startup even with preferredScaleId cleared, and the only route to the auxiliary role goes through a disconnect, which is what kills the emitter.

Suggested fix

Have onConnect() undo what simulateDisconnect() did:

@override
Future<void> onConnect() async {
  _stalled = false;
  _startEmission();
  _connectionSubject.add(ConnectionState.connected);
}

_startEmission() already cancels any existing timer, so calling it again is safe. MockBengle and MockDe1 are worth a look for the same shape.

Dominant language
Dart
Stars
61
Forks
28
Avg merge
1d 17h
Merged PRs (30d)
77

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from decentespresso/decaid

All issues in decentespresso/decaid

Similar issues

More Dart issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.