-Menü

Beiträge anzeigen

Dieser Abschnitt erlaubt es Ihnen, alle Beiträge anzusehen, die von diesem Mitglied geschrieben wurden. Beachten Sie, dass Sie nur Beiträge sehen können, die in Teilen des Forums geschrieben wurden, auf die Sie aktuell Zugriff haben.

Beiträge anzeigen-Menü

Themen - mattsches

#1
oscat.lib for q4Logix / Forenbereich löschen
26. April 2022, 12:42:35
Ich glaube, den Bereich hier kann man getrost löschen. Außer dem Ankündigungsthread ist seit fünf Jahren nichts passiert, und die News auf der Seite von qmd4 enden im Jahr 2017 (https://www.qmd4.com/index.php/news.html). OSCAT-Bibliotheken dürfte es für dieses System kaum geben, geschweige denn Nutzer, die sich hier darüber austauschen würden.
#2
Hallo,

wie beim neuen Wetterbaustein für Weatherbit.io bereits erwähnt (siehe http://www.oscat.de/community/index.php/topic,4952.0.html) habe ich einen neuen Bausteinen für das Parsen von JSON-Streams geschrieben. Gedankliche Vorlage war der XML_READER, der Aufbau und die Ansteuerung unterscheiden sich allerdings doch ziemlich gegenüber diesem.

Ich rechne nicht damit, dass die breite Masse Verwendung für einen solchen Baustein hat, daher spare ich mir eine genauere Beschreibung an dieser Stelle. Sollte hierfür Bedarf bestehen, bitte einfach melden, dann liefere ich sie gerne nach.

peewit, du könntest dir überlegen, ob der Bausteinen einen Platz in einer neuen Version der network.lib finden soll, dann sinnvollerweise gemeinsam mit dem Weatherbit-Baustein. Die Doku kann ich dann gerne übernehmen; die Portierung auf Steuerungssysteme abseits von CODESYS müssten dann andere Mitglieder der OSCAT-Community übernehmen, die dafür Verwendung haben.

Der JSON_READER ist als CODESYS V2.3/TwinCAT 2-Export angehängt. Eine CODESYS V3.5-Variante kann ich gerne bei Bedarf nachliefern.

Cheers,
mattsches
#3
Hallo zusammen,

nachdem openweathermap.org auch für die bestehenden API Keys die tagesgenaue Wettervorhersage abgeschaltet hat, stand ich wieder einmal vor dem Problem, keine Wetterdaten zu bekommen. Yahoo und World Weather sind ja bekanntlich schon länger tot.

Also habe ich mich mal wieder an das Thema gesetzt und einen neuen Baustein geschrieben. Dieses Mal für Weatherbit.io. Dort enthält der kostenlose API-Zugang die tagesgenauen Daten - hoffen wir, dass das so bleibt.

Eine kleine Hürde war die Bereitstellung der Daten durch den Dienst. Weatherbit.io liefert (wie zwischenzeitlich viele andere Dienste auch) die Daten nicht im XML-, sondern im JSON-Format aus. Also musste im selben Zuge noch ein JSON-Parser her.

Zum Wetterbaustein: Die Handhabung ist ähnlich wie bei YAHOO_WEATHER:


  • Variable anlegen, in der die Wetterdaten bereitgestellt werden sollen (Typ WEATHERBIT_DATA)
  • Gewünschten Ort mittels CITY_ID an den Baustein übergeben (Liste mit verfügbaren IDs siehe https://www.weatherbit.io/api/meta)
  • API Key übergeben (dazu bei Weatherbit registrieren unter https://www.weatherbit.io/account/create)
  • IP_C, S_BUF, R_BUF und IP_CONTROL-Aufruf wie bei YAHOO_WEATHER beschrieben
  • Start der Abfrage mittels positiver Flanke an ACTIVATE

Es werden Daten für den aktuellen und die vier folgenden Tage abgerufen. Einheiten sind metrisch + °C; Imperial und Fahrenheit habe ich mir gespart, könnten aber leicht nachgerüstet werden.

Der neue JSON_READER wird vom Weatherbit-Baustein intern genutzt und ist in der angehängten Exportdatei bereits enthalten.

Das Ganze gibt es aktuell für CODESYS V2.3/TwinCAT 2. Eine Portierung auf CODESYS V3.5 ist sehr einfach möglich, eine angepasste Quelle kann ich bei Bedarf gerne nachliefern.

Bitte habt bei Fragen Verständnis, dass ich u. U. nicht sofort antworte. Ich schaue hier nicht unbedingt jeden Tag rein, schon gar nicht bei dem Wetter.  ;D

Viel Spaß!
#4

Update: Zwischenzeitlich habe ich einen neuen Baustein für die Abfrage von Wetterdaten von Weatherbit.io erstellt. Damit ist eine zumindest aktuell funktionierende Alternative gefunden. Details siehe hier: http://www.oscat.de/community/index.php/topic,4952.0.html

Achtung, openweathermap.org hat die Lizenzpolitik dahingehend geändert, dass die vom Baustein genutzte 16 Tage-Vorhersage nun nicht mehr mit dem kostenfreien API-Key nutzbar ist. Leider kann auch nicht einfach auf die weiterhin kostenfreie 5 Tage/3 Stunden-Vorhersage umgebaut werden, da dort keine zusammenfassenden Werte pro Tag verfügbar sind, sondern ausschließlich die 3 Stunden-Abschnitte. Zudem sind bei der daraus resultierenden Größe der XML-Antwort Probleme mit der NETWORK_BUFFER-Variable zu erwarten, deren Standardlänge dann nicht ausreichen wird.

Ich habe derzeit keine schlüssige Idee, wie hier weiter verfahren werden könnte. Möglicherweise landet der Baustein nach dann recht kurzer Lebenszeit doch wieder in der Tonne.


Hallo zusammen,

nachdem worldweather.com nun auch die alten kostenlosen APIs abgeschaltet hat, war ich auf der Suche nach einer Alternative. Fündig wurde ich bei www.openweathermap.org, wo es weiterhin kostenlose APIs mit Zugriff auf verschiedene Vorhersagen gibt. Man registriert sich, erhält - wie gewohnt - einen API Key und kann loslegen.

Die Angabe des Ortes, für den die Vorhersage bezogen werden soll, erfolgt gemäß Empfehlung des Wetterdienstes mittels City ID. Eine Liste der verfügbaren IDs findet sich unter hier: http://bulk.openweathermap.org/sample/city.list.json.gz

Bausteine für Beschreibung und Icons habe ich vorerst nicht erstellt, weil

a) die Beschreibung für die einzelnen Tage direkt vom Wetterbaustein in die Struktur geschrieben wird und ich
b) keine Icons in Verwendung habe.

Wer mag, kann das natürlich gerne ergänzen.

Doku gibt es auch (noch?) keine, wer die Bausteine für Yahoo und WorldWeather kennt, dürfte auch mit der OpenWeatherMap-Variante zurecht kommen.

Ich habe den Baustein auf einer Beckhoff in Betrieb. Durch die Verwendung von IP_CONTROL etc. sollte er aber auch auf "normalen" CODESYS-Steuerungen laufen, wenn ich das richtig verstehe. Habe ich aber nicht ausprobiert.

Feedback ist natürlich willkommen.

Cheers,
mattsches




Edit: Danke übrigens noch an das OSCAT-Team für die ganzen wertvollen Bausteine! Mit dem XML_READER, der ganzen IP_...-Infrastruktur und den anderen Wetterbausteinen als Vorlage war das Ganze recht schnell erledigt.




Edit 26.07.17: URL geändert, so dass immer nur fünf Tage abgefragt werden ("&cnt=5") und die Standard-Empfangspuffergröße auch bei Änderung des Standardverhaltens seitens des Anbieters ausreichend bleibt.



Edit 04.10.17: Länge des URL_PREFIX Strings korrigiert. Danke an Lightcommander für den Hinweis!



Edit 03.11.17: Hinweis auf geänderte Preispolitik aufgenommen.

[gelöscht durch Administrator]
#5
Hallo,

ein ganz simpler, kleiner Vorschlag: Neben den Bausteinen FILTER_MAV_W und _DW würde sich ein _R für Gleitkommawerte sehr gut machen. Wäre m. E. im Wesentlichen Copy & Paste, auch in der Doku. Ich kann die (sehr überschaubaren) Vorarbeiten gerne übernehmen, falls Ihr das möchtet.

Viele Grüße,

mattsches
#6
Hallo OSCAT-Team,

der FILTER_MAV_W ist ziemlich vermurkst worden. Array als 1..32 deklariert, die Laufvariable i läuft aber von 0 weg und nur bis N-1. Bei der Initialisierung dann

sum := Y * N;

Y ist das (spätere) Berechnungsergebnis. X wäre richtig. Insgesamt funktioniert er schlicht nicht.

Warum kopiert Ihr nicht einfach den Code vom FILTER_MAV_DW rüber? Der ist korrekt.

Man sollte dort allenfalls noch init mit FALSE initialisieren. Boolesche Variablen allokieren in Codesys 1 Byte (nicht 1 Bit), können daher also ohne Initialisierung durchaus undefiniert sein. Hatte ich gerade auf meiner Beckhoff.

Viele Grüße,

mattsches

P.S. Verstehe ich das richtig, dass die Bilbliotheken zwar Open Source sind (was ich sehr begrüße, wie überhaupt die gesamte Initiative!), die Pflege aber durch Einzelne geschieht? D.h. Fehler in Code oder Doku meldet man ausschließlich hier im Forum und kann sie nicht etwa direkt korrigieren (wie z. B. bei Wikipedia). Richtig?

Edit: Ich muss mich korrigieren, FILTER_MAV_DW scheint schon noch einen Fehler zu haben. Die Summenbildung (Variable sum), die im _W offenbar eingefügt wurde, wird benötigt. Allerdings muss die Initialisierung dann auch korrekt sein (siehe oben).
#7
Hallo zusammen,

ich habe seit einiger Zeit die Building Lib (danke dafür!) für die Steuerung unserer Raffstores. Dabei habe ich einige Dinge modifiziert, um das Verhalten besser an meine Vorstellungen anzupassen. Betroffen sind BLIND_SHADE, BLIND_CONTROL und BLIND_ACTUATOR. Vielleicht sind die Punkte ja für den einen oder anderen interessant. Weitere Details gerne bei Bedarf; doch bevor ich mir die Finger hier wund tippe, wollte ich erstmal sehen, ob überhaupt Interesse besteht.

Also los - Folgende Punkte habe ich für meine Zwecke geändert bzw. ergänzt:

  • Winkelberechnung auch für Raffstores, die beim Hochfahren nicht ganz senkrecht (0°) gestellt werden. In meinem Fall sind es 18°, der von BLIND_SHADE errechnete Winkel wurde daher nicht korrekt eingestellt.
  • Winkel- und Positionsangabe von der größenlosen Skalierung 0..255 umgestellt auf 0..90° (für meine Zwecke reicht 1° Auflösung völlig) und 0..100% (mit 100%=geöffnet).
  • Winkelberechnung in BLIND_SHADE erweitert um die Auswirkung des horizontalen Sonnenwinkels. Steht die Sonne beispielsweise bei 200°, also sehr weit im Süden, können die Raffstores auf der Westseite deutlich weiter geöffnet (bezogen auf den Lamellenwinkel) bleiben als auf der Südseite.
  • Zusätzliche Verzögerungszeit in BLIND_SHADE, um den Raffstore nach erkanntem Sonnenschein verzögert zu schließen.
  • ... und noch eine weitere Verzögerungszeit in BLIND_SHADE für die Schattenerkennung; sie führt dazu, dass kurz nach erkanntem Schatten (bei mir nach 10s) die Lamellen waagrecht gestellt werden, um die Sicht zu maximieren. Erst nach weiterer Verzögerung (tofShadeDelayPos, ehemals sun_delay) fährt die Jalousie dann hoch.

Und hier der Code:

BLIND_SHADE:

FUNCTION_BLOCK BLIND_SHADE
VAR_INPUT
UP, DN : BOOL;
S_IN : BYTE;
PI, AI : BYTE;
ENABLE : BOOL;
SUN : BOOL;
DIRECTION : REAL := 180.0;
ANGLE_OFFSET : REAL := 80.0;
DISABLE_TRACKING : BOOL := FALSE; (* disable tracking of sun/slat angle -> always maximize shading *)
END_VAR
VAR_IN_OUT
CX : CALENDAR;
END_VAR
VAR_INPUT CONSTANT
sunrise_offset : TIME := T#1h;
sunset_preset : TIME := T#1h;
slat_width : REAL := 80.0;
Slat_spacing : REAL := 70.0;
Shade_pos : BYTE := 0;

tSunDelay : TIME := t#60s; (* delay after sun detection until slat angle is calculated *)
tShadeDelayAngle : TIME := t#30s; (* delay after shade detection until slat angle is set to 90=horizontal *)
tShadeDelayPos : TIME := t#10m; (* delay after shade detection until slat position is set to 100=fully opened *)
END_VAR
VAR_OUTPUT
QU, QD : BOOL;
STATUS : BYTE;
PO, AO : BYTE;
END_VAR
VAR
angle: REAL;
max_angle : REAL;
angle_old : REAL;

fEffectiveSlatWidth : REAL; (* effective slat width, including effect of horizontal sun angle *)

tonSunDelay : TON; (* timer for delay after sun detection until shade is closed and angle is calculated *)
tofShadeDelayAngle : TOF; (* timer for delay after shade detection until slat angle is set to 90=horizontal *)
tofShadeDelayPos : TOF; (* timer for delay after shade detection until slat position is set to 100=fully opened *)

sun_ver_last : REAL; (* last vertical sun angle (for change detection) *)
sun_hor_last : REAL; (* last horizontal sun angle (dto.) *)
END_VAR



(* delay sun/shade detection in order to prevent shade from constantly going up and down *)
tonSunDelay(IN:=sun, PT:=tSunDelay);
tofShadeDelayAngle(IN:=tonSunDelay.Q OR tofShadeDelayAngle.Q AND sun, PT:=tShadeDelayAngle);
tofShadeDelayPos(IN:=tofShadeDelayAngle.Q, PT:=tShadeDelayPos);


IF UP AND DN AND enable AND (tonSunDelay.Q OR tofShadeDelayPos.Q)
AND cx.SUN_HOR > direction - angle_offset AND cx.SUN_HOR < direction + angle_offset
AND DT_TO_TOD(cx.UTC) > cx.SUN_RISE + sunrise_offset AND DT_TO_TOD(cx.UTC) < cx.SUN_SET - sunset_preset THEN
   status := 151;
   QU := UP;
   QD := DN;

   (* position is predefined *)
   po := shade_pos;

   (* shading is active now calculate the slat angle *)
   (* calculate the max angle for the blind *)
   fEffectiveSlatWidth := slat_width / COS(RAD(ABS(DIRECTION - cx.SUN_HOR)));
   max_angle := DEG(ATAN(slat_spacing / fEffectiveSlatWidth));

   (* check if sun angle is between 0 and max angle *)
   IF cx.SUN_VER > 0.0 AND cx.SUN_VER < max_angle AND NOT DISABLE_TRACKING AND tofShadeDelayAngle.Q THEN
      (* only recalculate blind angle if vertical sun angle has changed *)
      IF   cx.SUN_VER <> sun_ver_last OR cx.SUN_HOR <> sun_hor_last THEN
         angle := cx.SUN_VER + DEG(ACOS(COS(RAD(cx.SUN_VER))*slat_spacing / fEffectiveSlatWidth));
         sun_ver_last := cx.SUN_VER;         (* store current sun angles *)
         sun_hor_last := cx.SUN_HOR;
      END_IF;
      ao := INT_TO_BYTE(LIMIT(0,TRUNC(angle), 90));
   ELSIF DISABLE_TRACKING THEN               (* tracking of sun/slat angle disabled -> always maximize shading *)
      ao := 0;
   ELSE
      ao := 90;
   END_IF;
ELSE
   QU := UP;
   QD := DN;
   po := pi;
   ao := ai;
   status := S_IN;
END_IF;



BLIND_CONTROL:

FUNCTION_BLOCK BLIND_CONTROL
VAR_INPUT
UP, DN : BOOL;
S_IN : BYTE;
PI : BYTE;
AI : BYTE;
T_UD, T_ANGLE : TIME;
END_VAR
VAR_INPUT CONSTANT
SENS : BYTE := 5;
T_LOCKOUT: TIME := T#100ms;
MIN_ANGLE : BYTE := 0; (* minimum slat angle *)
MAX_ANGLE : BYTE := 90; (* maximum slat angle *)
END_VAR
VAR_OUTPUT
POS, ANG : BYTE;
MU, MD : BOOL;
STATUS : BYTE;
END_VAR
VAR
act : BLIND_ACTUATOR;
delta : BYTE;
bTimeTest:BOOL:=FALSE;
iPos:BYTE;
iAngel:BYTE;
END_VAR




(* limit angle setpoint *)
ai := LIMIT(MIN_ANGLE, ai, MAX_ANGLE);


(* Check Position*)
act(T_UD:=T_UD, T_ANGLE:=T_ANGLE, T_lockout := T_Lockout, MIN_ANGLE := MIN_ANGLE, MAX_ANGLE := MAX_ANGLE);

IF UP AND DN THEN
(* automatic modus detected *)
(* first find correct position *)
IF BYTE_TO_INT(act.pos) < BYTE_TO_INT(pi) - delta THEN
act.UP := TRUE;
act.DN := FALSE;
delta := 0;
STATUS := 121;
ELSIF BYTE_TO_INT(act.pos) > BYTE_TO_INT(pi) + delta THEN
act.UP := FALSE;
act.DN := TRUE;
delta := 0;
STATUS := 122;
(* regulate angle *)
ELSIF BYTE_TO_INT(act.ang) < BYTE_TO_INT(ai) - delta AND T_angle > T#100ms THEN
act.UP := TRUE;
act.DN := FALSE;
delta := sens/2;
STATUS := 123;
ELSIF BYTE_TO_INT(act.ang) > BYTE_TO_INT(ai) + delta AND T_angle > T#100ms THEN
act.UP := FALSE;
act.DN := TRUE;
delta := sens/2;
STATUS := 124;
(* correct position reached *)
ELSE
act.UP := FALSE;
act.DN := FALSE;
delta := sens;
STATUS := S_IN;
END_IF;
ELSE
act.UP := UP;
act.DN := DN;
STATUS := S_IN;
END_IF;

(* blind control calls blind_actuator *)
act(T_UD:=T_UD, T_ANGLE:=T_ANGLE, T_lockout := T_Lockout);
pos := act.pos;
ang := act.ang;
MU := act.QU;
md := act.QD;



BLIND_ACTUATOR:

FUNCTION_BLOCK BLIND_ACTUATOR
VAR_INPUT
UP, DN : BOOL;
S_IN : BYTE;
T_UD : TIME := T#10s;
T_ANGLE : TIME := T#3s;
MIN_ANGLE : BYTE := 0; (* minimum slat angle; 0 would equal full vertical position *)
MAX_ANGLE : BYTE := 90; (* maximum slat angle; 90 would equal horizontal position *)
END_VAR
VAR_INPUT CONSTANT
T_LOCKOUT : TIME := t#100ms;
END_VAR
VAR_OUTPUT
POS, ANG : BYTE;
QU, QD : BOOL;
STATUS : BYTE;
END_VAR
VAR
position, angle : RMP_B;
lock : INTERLOCK;
END_VAR



(* make sure only one moto r is active at a given time *)
lock(i1 := UP, I2 := DN, TL := T_lockout);

(* ramp up or down to simulate the angle position of the blind slats *)
angle(e := lock.Q1 OR lock.Q2, UP := lock.Q1, PT := T_Angle);
position(e := lock.Q1 AND angle.high OR lock.Q2 AND angle.low, up := lock.Q1, PT := T_UD);

(* set the outputs *)
pos := position.Out * 100 / 255;
ang := angle.OUT * (MAX_ANGLE - MIN_ANGLE) / 255 + MIN_ANGLE;


(* set the outputs *)
QU := lock.Q1;
QD := lock.Q2;

(* set the status output *)
IF UP AND DN THEN
status := 1; (* error up and down together are not allowed *)
ELSIF UP THEN
status := 121;
ELSIF DN THEN
status := 122;
ELSE
status := S_IN;
END_IF;