Jump to content

Temperatur und Luftdruck liefern plötzlich falsche Werte


André K.

Recommended Posts

Kann ich denn davon ausgehen, daß sich das Bricklet dann im Initialzustand befindet? Oder sollte ich da vorher am besten noch eine Art Reset/Wipe auslösen, wenn das geht?

Bei einem Verlust der IP-Connection habe ich das übrigens folgendermaßen gelöst:

void cb_connected(uint8_t reason, void *user_data)
{
	syslog(LOG_INFO, "Connection to brickd (re)established (reason=%i)", reason);

	/* Bei einem Reconnect Aufzählung (und damit Initialisierung) neu anstoßen: */
	if(reason == IPCON_CONNECT_REASON_AUTO_RECONNECT) ipcon_enumerate(&bd_conn);
}

Da baue ich aber auch im Vertrauen darauf, daß sich die Bricklets "hoffentlich" alle noch im Initialzustand befinden — was aber natürlich nicht der Fall sein muß. Wenn sich jemand per Brick Viewer verbindet und eine Einstellung ändert die ich nicht extra initialisiere weil der Default OK ist wird die Einstellung vermutlich auch so bleiben …

Wie macht man sowas am elegantesten?

André

Link zu diesem Kommentar
Share on other sites

Wenn das Bricklet die Enumeration (mit -Type Connected) schickt, sollte es im Initialzustand sein, alles andere wäre ein Firmware-Bug. D.h. wenn du danach deine Abweichungen zum Initialzustand konfiguriest sollte das reichen. Bei einem Reconnect der IP-Connection kann es im worst-case natürlich sein, dass während du nicht verbunden warst, eins der Bricklets neugestartet wurde, um maximal robust zu sein musst du da also auch alles was du brauchst neu konfigurieren.

Wenn sich jemand anderes per Brick Viewer verbindet und Konfiguration verstellt hast du verloren, das bekommst du nur in den Griff, wenn du die Bricklets resettest und danach neu konfigurierst. Da würde ich lieber die Authentication anschalten ;)

Link zu diesem Kommentar
Share on other sites

vor 22 Minuten schrieb rtrbt:

Bei einem Reconnect der IP-Connection kann es im worst-case natürlich sein, dass während du nicht verbunden warst, eins der Bricklets neugestartet wurde, um maximal robust zu sein musst du da also auch alles was du brauchst neu konfigurieren.

Das passiert ja eh, denn bei einem Reconnect wird ja ipcon_enumerate() aufgerufen, und das Enumerate-Callback sieht so aus:

void cb_enumerate(const char *uid, const char *uplink_uid, char pos, uint8_t hw_vers[3], uint8_t fw_vers[3], uint16_t did, uint8_t enume_type, void *user_data)
{
	/* Nur auf manuell angestoßene Aufzählungen reagieren: */
	if(enume_type == IPCON_ENUMERATION_TYPE_AVAILABLE) switch (did)
	{
		case AMBIENT_LIGHT_V3_DEVICE_IDENTIFIER:
			if (cfg_dumpmode) printf("Found %s with UID=%s\n", AMBIENT_LIGHT_V3_DEVICE_DISPLAY_NAME, uid);

			/* Wurde der Speicher noch nicht allokiert? */
			if (bl_light == NULL) bl_light = new AmbientLightV3;
			else ambient_light_v3_destroy(bl_light);
			ambient_light_v3_create(bl_light, uid, &bd_conn);

			/* Konfiguration: 0-64000 Lux (= kein Gain), 150ms (Default laut Datenblatt: 100ms) */
			ambient_light_v3_set_configuration(bl_light, AMBIENT_LIGHT_V3_ILLUMINANCE_RANGE_64000LUX, AMBIENT_LIGHT_V3_INTEGRATION_TIME_150MS);
			ambient_light_v3_set_status_led_config(bl_light, AMBIENT_LIGHT_V3_STATUS_LED_CONFIG_OFF);

			/* Callback für Umgebungshelligkeit: 1s */
			ambient_light_v3_register_callback(bl_light, AMBIENT_LIGHT_V3_CALLBACK_ILLUMINANCE, (void (*)(void))cb_illuminance, NULL);
			ambient_light_v3_set_illuminance_callback_configuration(bl_light, 1000, true, AMBIENT_LIGHT_V3_THRESHOLD_OPTION_OFF, 0, 0);
			break;

Und dann folgen halt noch CASEs für sämtliche andere Bricklets die so zum Einsatz kommen.

Vielleicht reicht es ja schon, einfach das if (enum_type == …) wegzulassen? Ich weiß gerade gar nicht mehr warum ich das da eingebaut habe xD

André

Link zu diesem Kommentar
Share on other sites

13 minutes ago, André K. said:

Vielleicht reicht es ja schon, einfach das if (enum_type == …) wegzulassen? Ich weiß gerade gar nicht mehr warum ich das da eingebaut habe xD

Wenn du das weglässt, konfigurierst du auch alles, wenn du eine Enumerierung mit ENUMERATION_TYPE_DISCONNECTED bekommst, da sollte aber der Code auf keinen Fall laufen.

Ansonsten gebe ich dir recht, wenn du eine Enumeration bei einem Reconnect auslöst, brauchst du sonst keine Spezialbehandlung.

Link zu diesem Kommentar
Share on other sites

Am 22.6.2020 um 16:10 schrieb rtrbt:

Wenn du das weglässt, konfigurierst du auch alles, wenn du eine Enumerierung mit ENUMERATION_TYPE_DISCONNECTED bekommst, da sollte aber der Code auf keinen Fall laufen.

Hast natürlich Recht, deshalb habe ich das if() wohl auch drin. ;)

So ganz klar ist mir der ENUMERATION_TYPE_DISCONNECTED übrigens noch nicht. Ist damit der Fall gemeint, daß ein einzelnes Bricklet weg ist, also wenn ich im Laufenden Betrieb den Stecker ziehen würde? Oder ist das sozusagen die "USB-Version" vom IPCON_CALLBACK_DISCONNECTED, das es ja auch noch gibt? Also wenn ich das USB-Kabel des Stapels vom Rechner abziehe? In der Doku steht ja auch der Hinweis "Nur bei USB-Verbindungen möglich".

André

Link zu diesem Kommentar
Share on other sites

1 hour ago, André K. said:

Ist damit der Fall gemeint, daß ein einzelnes Bricklet weg ist, also wenn ich im Laufenden Betrieb den Stecker ziehen würde?

Nein, das wird nicht unterstützt.

1 hour ago, André K. said:

Oder ist das sozusagen die "USB-Version" vom IPCON_CALLBACK_DISCONNECTED, das es ja auch noch gibt? Also wenn ich das USB-Kabel des Stapels vom Rechner abziehe?

Das kommt hin, ein Unterschied ist aber, dass du das Enumerate auch für Teile der Hardware bekommen kannst, du kannst ja zwei Stacks per USB angeschlossen haben und dann einen abziehen.

Link zu diesem Kommentar
Share on other sites

  • 3 weeks later...
Am 22.6.2020 um 10:09 schrieb rtrbt:

Moin,

Das kann eigentlich nur passieren, wenn du entweder einen Code-Pfad hast, der das Callback deaktiviert, oder wenn das Bricklet aus irgendwelchen Gründen beschlossen hat, sich zu resetten. Hast du eventuell ein sporadisches Enumerate vom Bricklet gesehen, bevor keine Daten mehr kamen? Wenn das Bricklet ein Enumerate mit dem Enumeration-Type ENUMERATION_TYPE_CONNECTED (=1) schickt, dann hat es sich neugestartet.

Erik

Gestern Abend ist der Fall wieder passiert …

Leider hatte ich unterdessen noch keine Zeit, die Ergänzung in meinen Daemon einzubauen. Aber ich bin mir gar nicht mehr sicher, ob ein Spontan-Reset überhaupt der Grund sein kann.

Wie es sich gestern geäußert hat: Das Temperature-Bricklet 2.0 hat gegen kurz nach 20 Uhr, wie beim letzten Vorfall im Juni auch, einfach keine neuen Werte mehr geliefert, der zuletzt gelieferte Wert war 20,6°C. Gegen 23:30 Uhr ist es mir dann aufgefallen. Ich habe mich dann per Brick-Viewer aufgeschaltet. Der Graph auf dem Tab des Temperetaure-Bricklets wurde wie gewohnt Stück für Stück gezeichnet, allerdings als Gerade, und mit besagten 20,6°C. Der Brick-Viewer fragt doch per getter ab, oder?

Es brauchte zwei Resets, bis es wieder da war, und die zu dieser Zeit korrekte Temperatur von irgendwas bei 10 Grad anzeigte. Kann das dann überhaupt der vermutete spontane Reset sein?

André 

Link zu diesem Kommentar
Share on other sites

Moin,

21 hours ago, André K. said:

Der Brick-Viewer fragt doch per getter ab, oder?

Das stimmt, also wurde dein Callback nicht einfach durch einen Reset deaktiviert. Soweit ich das aus der Firmware des Bricklets sehe, gibt es zwei Möglichkeiten was da passiert:

  1. Der Sensor selbst bleibt auf einem Wert hängen und gibt diesen aus irgendeinem Grund immer zurück. (Halte ich für unwahrscheinlich)
  2. Die I2C-Kommunikation zwischen Sensor und Bricklet-Prozessor ist gestört und zwar so, dass die Fehlerbehandlung der Bricklet-Firmware das nicht wieder repariert bekommt. Eventuell ist ein Bug in der Firmware, der die Kommunikations-State-Machine so durcheinander bringt, dass das Bricklet in einer Reinitialisierungsschleife hängt o.Ä.

Auf deiner Seite ist das vermutlich nur zu lösen, wenn du den Wert in deinem Programm überwachst und wenn er untypisch lange hängt das Bricklet resettest. Mir ist aber auch unklar, warum es bei dir zwei Resets braucht. Hast du eventuell nach dem ersten nicht lang genug gewartet?

Ich stelle hier mal einen Aufbau mit einem Temperature Bricklet 2.0 hin, eventuell bekomme ich das Problem reproduziert. Welche Callback-Konfiguration benutzt du für das Bricklet?

Link zu diesem Kommentar
Share on other sites

vor 4 Stunden schrieb rtrbt:

Mir ist aber auch unklar, warum es bei dir zwei Resets braucht. Hast du eventuell nach dem ersten nicht lang genug gewartet?

Das will ich nicht ganz ausschließen, und so ganz habe ich das mit dem Reset eh noch nicht durchschaut. Es ist ja auf jedem Tab ein eigener Reset-Button vorhanden, aber mein Eindruck ist, daß immer der ganze Stapel resettet wird. Kann das sein? Also daß es quasi egal ist, wo man den Button drückt?

vor 4 Stunden schrieb rtrbt:

Welche Callback-Konfiguration benutzt du für das Bricklet?

Ich poste einfach mal den relevanten Teil aus dem Quelltext:

temperature_v2_create(bl_thermo_v2, uid, &bd_conn);

/* Status-LED ausschalten: */
temperature_v2_set_status_led_config(bl_thermo_v2, TEMPERATURE_V2_STATUS_LED_CONFIG_OFF);

/* Callback für Temperatur: 1s */
temperature_v2_register_callback(bl_thermo_v2, TEMPERATURE_V2_CALLBACK_TEMPERATURE, (void (*)(void))cb_temperature, NULL);
temperature_v2_set_temperature_callback_configuration(bl_thermo_v2, 1000, true, TEMPERATURE_V2_THRESHOLD_OPTION_OFF, 0, 0);

Schon mal vielen Dank!

André

Link zu diesem Kommentar
Share on other sites

On 7/14/2020 at 8:33 PM, André K. said:

Das will ich nicht ganz ausschließen, und so ganz habe ich das mit dem Reset eh noch nicht durchschaut. Es ist ja auf jedem Tab ein eigener Reset-Button vorhanden, aber mein Eindruck ist, daß immer der ganze Stapel resettet wird. Kann das sein? Also daß es quasi egal ist, wo man den Button drückt?

Das hängt davon ab was für ein Brick/Bricklet das ist, bei dem du den Button drückst. Wenn du einen Brick oder ein altes 10-Pol-Bricklet resettest, startet der ganze Stapel neu. Wenn es ein 7-Pol-Bricklet ist, dann nur das Bricklet selbst.

On 7/14/2020 at 8:33 PM, André K. said:

Ich poste einfach mal den relevanten Teil aus dem Quelltext:

Danke, ich baue das hier mal nach. Falls sich da was tut, melde ich mich nochmal.

Link zu diesem Kommentar
Share on other sites

Vorhin ist es wieder aufgetreten, ich hab mal ein kurzes Bildschirmvideo gemacht ... nach dem Reset verschwindet das Bricklet aus der Liste, nachdem man sich neu verbindet ist es dann wieder zu sehen und arbeitet auch normal.

(Video ist etwas klein geraten, ich hoffe man erkennt es trotzdem)

Link zu diesem Kommentar
Share on other sites

Moin,

Das das Bricklet nach dem Reset nicht wieder auftaucht liegt vermutlich daran, dass dessen Enumerate-Paket verloren gegangen ist. Wenn du Reconnectest, löst das auch eine Enumerierung aus, dann taucht das Bricklet wieder auf.

Bezüglich der hängenden Temperatur selbst: Teste mal bitte die angehangene Firmware, die I2C-Kommunikationsfehler subtil anders behandelt, eventuell löst das dein Problem. Ich habe meinen Aufbau hier auch darauf umgestellt.

temperature-v2-bricklet-firmware.zbin

Link zu diesem Kommentar
Share on other sites

vor 7 Stunden schrieb rtrbt:

Das macht der Brick Viewer für dich.

Hat funktioniert, nachdem das Problem heute Mittag wieder aufgetreten war — irgendwie häuft es sich … aber dann sehen wir wenigstens, ob es eine Besserung bringt.

PS: Hab das Update tatsächlich ohne vorigen Reset des Bricklets eingespielt, danach war es dann auch wieder "lebendig".

André

Link zu diesem Kommentar
Share on other sites

  • 2 weeks later...

Heute Morgen ist der Fehler wieder aufgetreten …

Anders als die letzten Male reichte jetzt aber ein Connect vom Brick-Viewer, um das Bricklet wieder zum Leben zu erwecken. Ich musste also nicht auf den Reset-Button klicken.

Ob es wirklich der Brick-Viewer war, oder mein Daemon (der ja jedes Mal eine Initialisierung vornimmt wenn ein ENUMERATE angestoßen wurde, was beim Connect vom Viewer ja passiert) kann ich natürlich nicht genau sagen …

André

Link zu diesem Kommentar
Share on other sites

Moin,

Der Fehler war auch wieder, dass du über Minuten zwar Callbacks bekommen hast, aber die immer den selben Wert hatten? (Im Gegensatz zu du hast keine Callbacks mehr bekommen)

Was macht dein Daemon mit dem Bricklet wenn ein Enumerate kommt? Nur Callbacks registrieren oder einen Reset oder den Heater an oder sowas? Das allein eine Enumerierung und ein Callback-Neuregistrieren eine eventuell hängendes I2C wiederbelebt ergäbe keinen Sinn, dann müssten wir die These wohl zu Grabe tragen.

Gruß,
Erik

Link zu diesem Kommentar
Share on other sites

vor 3 Minuten schrieb rtrbt:

Der Fehler war auch wieder, dass du über Minuten zwar Callbacks bekommen hast, aber die immer den selben Wert hatten?

Nee, Callbacks gab es (wie zuvor auch) keine mehr, das Bricklet ist quasi "verstummt" so als ob sich die Temperatur nicht ändern würde.

Dies ist meine kompletter Enumerate-Callback-Handler, es fehlen lediglich die CASEs für die ganzen anderen Bricklets:

void cb_enumerate(const char *uid, const char *uplink_uid, char pos, uint8_t hw_vers[3], uint8_t fw_vers[3], uint16_t did, uint8_t enume_type, void *user_data)
{
	/* Nur auf manuell angestoßene Aufzählungen reagieren: */
	if(enume_type == IPCON_ENUMERATION_TYPE_AVAILABLE) switch (did)
	{
		case TEMPERATURE_V2_DEVICE_IDENTIFIER:
			if (cfg_dumpmode) printf("Found %s with UID=%s\n", TEMPERATURE_V2_DEVICE_DISPLAY_NAME, uid);

			/* Wurde der Speicher noch nicht allokiert? */
			if (bl_thermo_v2 == NULL) bl_thermo_v2 = new TemperatureV2;
			else temperature_v2_destroy(bl_thermo_v2);
			temperature_v2_create(bl_thermo_v2, uid, &bd_conn);

			/* Status-LED ausschalten: */
			temperature_v2_set_status_led_config(bl_thermo_v2, TEMPERATURE_V2_STATUS_LED_CONFIG_OFF);

			/* Callback für Temperatur: 1s */
			temperature_v2_register_callback(bl_thermo_v2, TEMPERATURE_V2_CALLBACK_TEMPERATURE, (void (*)(void))cb_temperature, NULL);
			temperature_v2_set_temperature_callback_configuration(bl_thermo_v2, 1000, true, TEMPERATURE_V2_THRESHOLD_OPTION_OFF, 0, 0);
			break;

		default:
			if (cfg_dumpmode) printf("Found other Device: DID=%d UID=%s\n", did, uid);
			break;
	}
	else
	{
		/* Nicht behandelte Aufzählung loggen: */
		packet_enqueue(VALUE_EVENT, EV_UNHANDLED_ENUM);
		syslog(LOG_INFO, "Unhandled enumeration: type=%i DID=%d UID=%s", enume_type, did, uid);
	}
}

Könnte das Beeinflussen der LED was bewirkt haben?

André

Link zu diesem Kommentar
Share on other sites

43 minutes ago, André K. said:

Könnte das Beeinflussen der LED was bewirkt haben?

Nein die Nachricht geht nur an das Bricklet, nicht an den Sensor selbst.

Am Code fallen mir spontan zwei Dinge auf:

  1. Da deine Callbacks value_has_to_change=true haben, ist nicht so richtig unterscheidbar, ob die Temperatur gleich ist oder das Bricklet nicht mehr kommuniziert. Würde der Rest deiner Software das überstehen, da false mitzugeben? Dann kannst du auch viel strikter das Bricklet resetten, wenn z.b. 10 Sekunden lang kein Wert mehr kam.
  2. Du reagierst nur auf IPCON_ENUMERATION_TYPE_AVAILABLE, wenn das Bricklet sich neu startet (warum auch immer) bekommst du aber _CONNECTED. Da musst du auch die Callbacks neu registrieren usw.

Hast du in deinem Log die Unhandled enumeration Meldung bekommen?

 

Link zu diesem Kommentar
Share on other sites

vor 8 Minuten schrieb rtrbt:

Hast du in deinem Log die Unhandled enumeration Meldung bekommen?

Bislang kein einziges Mal, weder im Syslog noch in der Datenbank. Dieser else-Zweig ist allerdings erst seit der Version vom 22. Juli drin.

Übrigens, während wir hier schreiben ist es wieder aufgetreten ;) bzw. heute morgen um kurz vor 10, ich hab da so eine interne Statusseite auf der ich nachsehen kann wann zuletzt was eingetrudelt ist:

836052133_Bildschirmfoto2020-07-31um15_10_21.png.c85231f17cda2cb4fd76d3bddb29debc.png

("Temperatur 2" ist übrigens der Wert vom Humidity-Bricklet)

Soll ich noch irgendwas spezielles testen, bevor ich gleich per Brick-Viewer drauf gehe?

André

Link zu diesem Kommentar
Share on other sites

vor 17 Stunden schrieb rtrbt:

Bevor du mit dem Brick-Viewer drauf gehst frag mal (mit einem Python-Script oder sowas) die Callback-Konfiguration und die aktuelle Temperatur ab (jeweils mit dem Getter, nicht die Temperatur per Callback abfragen).

Habe ich jetzt mal gemacht, mit (für mich) durchaus überraschendem Ergebnis: Per getter erhalte ich tatsächlich einen plausiblen Wert, der sich auch von Aufruf zu Aufruf geringfügig ändert.

Aber: Das Bricklet hat anscheinend die Callback-Config vergessen, und auch die Status-LED-Config ist auf dem Defaultwert 3.

Das hier ist das komplette Test-Skript:

require_once('Tinkerforge/IPConnection.php');
require_once('Tinkerforge/BrickletTemperatureV2.php');

use Tinkerforge\IPConnection;
use Tinkerforge\BrickletTemperatureV2;

const HOST = '192.168.1.105';
const PORT = 4223;
const UID = 'KEv'; // Change XYZ to the UID of your Temperature Bricklet 2.0

$ipcon = new IPConnection(); // Create IP connection
$t = new BrickletTemperatureV2(UID, $ipcon); // Create device object

$ipcon->connect(HOST, PORT); // Connect to brickd

// Get current temperature
$temperature = $t->getTemperature();
echo "Temperature: " . $temperature/100.0 . " °C\n";

echo "Callback configuration:\n";
$conf = $t->getTemperatureCallbackConfiguration();
var_dump($conf);

echo "LED status:\n";
$led_status = $t->getStatusLEDConfig();
var_dump($led_status);

echo "Error status:\n";
$error_status = $t->getSPITFPErrorCount();
var_dump($error_status);

echo "Press key to exit\n";
fgetc(fopen('php://stdin', 'r'));
$ipcon->disconnect();

Und das hier die komplette Ausgabe:

Temperature: 24.5 °C
Callback configuration:
array(5) {
  ["period"]=>
  int(0)
  ["value_has_to_change"]=>
  bool(false)
  ["option"]=>
  string(1) "x"
  ["min"]=>
  int(0)
  ["max"]=>
  int(0)
}
LED status:
int(3)
Error status:
array(4) {
  ["error_count_ack_checksum"]=>
  int(0)
  ["error_count_message_checksum"]=>
  int(0)
  ["error_count_frame"]=>
  int(0)
  ["error_count_overflow"]=>
  int(0)
}
Press key to exit

So, und nachdem ich mich anschließend via Brick-Viewer verbunden habe (und damit die Enumeration getriggert habe) kamen auch sofort wieder Callbacks an, ohne zusätzlichen Reset. Und das kleine PHP-Skript hat dann auch die korrekte Callback-Config geliefert:

Callback configuration:
array(5) {
  ["period"]=>
  int(1000)
  ["value_has_to_change"]=>
  bool(true)
  ["option"]=>
  string(1) "x"
  ["min"]=>
  int(0)
  ["max"]=>
  int(0)
}
LED status:
int(0)

Ich hoffe, mit diesen Infos kannst Du was anfangen. ;)

André

Link zu diesem Kommentar
Share on other sites

Update 😅

Diesmal hat es nur 15 Minuten gedauert bis zum erneuten Auftreten … gleiches Bild, Callback-Config "vergessen" aber jetzt wurde ein "error_count_frame" gezählt:

Error status:
array(4) {
  ["error_count_ack_checksum"]=>
  int(0)
  ["error_count_message_checksum"]=>
  int(0)
  ["error_count_frame"]=>
  int(1)
  ["error_count_overflow"]=>
  int(0)
}

André

Link zu diesem Kommentar
Share on other sites

On 8/1/2020 at 9:07 AM, André K. said:

Das Bricklet hat anscheinend die Callback-Config vergessen, und auch die Status-LED-Config ist auf dem Defaultwert 3.

Das ist für mich ein sehr starker Indikator dafür, dass das Bricklet sich resettet. Mir ist nur unklar warum das so oft passiert und warum du die Enumerations nicht siehst, wenn es wieder kommt.

Link zu diesem Kommentar
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Gast
Reply to this topic...

×   Du hast formatierten Text eingefügt.   Formatierung jetzt entfernen

  Only 75 emoji are allowed.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Clear editor

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

×
×
  • Neu erstellen...