Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Tester
    4. Test Adapter iQontrol 2.0.x Vis (Entwicklungs-Thread)

    NEWS

    • 15. 05. Wartungsarbeiten am ioBroker Forum

    • Monatsrückblick - April 2025

    • Minor js-controller 7.0.7 Update in latest repo

    Test Adapter iQontrol 2.0.x Vis (Entwicklungs-Thread)

    This topic has been deleted. Only users with topic management privileges can see it.
    • da_Woody
      da_Woody @s.bormann last edited by da_Woody

      @s-bormann alder, das zeigst du jetzt erst??? peitsche.gif
      gerade instet, mal guxxen, wie ich damit zurechtkomme... im RAW rumfummeln macht auch nicht gerade laune bei >80 geräten x menge DP... knud.gif

      hmpf.

      host.ioBroker	2021-03-12 20:44:23.873	error	system.adapter.alias-manager.0 invalid mode
      
      s.bormann 1 Reply Last reply Reply Quote 1
      • B
        Beowolf @s.bormann last edited by Beowolf

        @s-bormann sagte in Test Adapter iQontrol 1.6.x Vis:

        @beowolf sagte in Test Adapter iQontrol 1.6.x Vis:

        @s-bormann

        31 geht. Ist aber etwas unschön jetzt bei allen Regler die max Temp zu ändern. 😕

        Das stimmt. Dann nutze die andere Variante. Die kannst Du mit wenigen Klicks für alle Thermostate auf einmal ändern:
        a972da5e-d5cd-42b8-a488-867e63a3f6e2-image.png
        d02ad9d4-7735-4fea-a46e-3252b70a6bed-image.png

        Und:
        6eac7745-233e-4984-bfbe-c360d3639ef4-image.png
        7d8d4b3c-d973-4d2a-9d9c-6afcdb434321-image.png

        Das ändern für alle Thermostate und Homematicthermostate die Bedingngen für eine aktive Gerätekachel auf "größer oder gleich" "5°". Das sollte dann denke ich passen.

        Vorher aber bitte ein Backup anlegen, falls was nicht passt!

        Du hast den Wert "batteryActiveConditionValue" ausgewählt. Das ist doch bestimmt nicht richtig, oder?

        Das ist sicher gemeint, oder "tileActiveConditionValue" ?

        s.bormann 1 Reply Last reply Reply Quote 0
        • s.bormann
          s.bormann Most Active @Beowolf last edited by

          @beowolf sagte in Test Adapter iQontrol 1.6.x Vis:

          @s-bormann sagte in Test Adapter iQontrol 1.6.x Vis:

          @beowolf sagte in Test Adapter iQontrol 1.6.x Vis:

          @s-bormann

          31 geht. Ist aber etwas unschön jetzt bei allen Regler die max Temp zu ändern. 😕

          Das stimmt. Dann nutze die andere Variante. Die kannst Du mit wenigen Klicks für alle Thermostate auf einmal ändern:
          a972da5e-d5cd-42b8-a488-867e63a3f6e2-image.png
          d02ad9d4-7735-4fea-a46e-3252b70a6bed-image.png

          Und:
          6eac7745-233e-4984-bfbe-c360d3639ef4-image.png
          7d8d4b3c-d973-4d2a-9d9c-6afcdb434321-image.png

          Das ändern für alle Thermostate und Homematicthermostate die Bedingngen für eine aktive Gerätekachel auf "größer oder gleich" "5°". Das sollte dann denke ich passen.

          Vorher aber bitte ein Backup anlegen, falls was nicht passt!

          Du hast den Wert "batteryActiveConditionValue" ausgewählt. Das ist doch bestimmt nicht richtig, oder?

          Das ist sicher gemeint, oder "tileActiveConditionValue" ?

          Ja, hast natürlich Recht!

          1 Reply Last reply Reply Quote 0
          • M
            martinschm @s.bormann last edited by martinschm

            @s-bormann said in Test Adapter iQontrol 1.6.x Vis:

            @kueppert sagte in Test Adapter iQontrol 1.6.x Vis:

            @da_woody hab ich auch gemacht. War viel Arbeit, aber vereinfacht Skripte, VIS, iQontrol etc bei Gerätewechseln ungemein ^^ einfach im RAW den DP (das Gerät) anpassen, fertig

            Ich habe auch viele Aliase angelegt. Aber mit dem aktuellen Devices-Adapter kam ich nicht so klar, deshalb habe ich die meisten "von Hand" angelegt. Dann musste ich einige Änderungen durchführen - und hätte alle Datenpunkte wieder von Hand anpacken müssen. Deshalb habe ich mir einen einfachen Adapter geschrieben, mit dem man Aliase einfacher bearbeiten kann. Vielleicht hilft es ja auch dem ein oder anderen:

            https://github.com/sbormann/ioBroker.alias-manager

            Alias-Manager

            8b270fc8-a339-4785-8384-d331cc0ee8b4-image.png

            Genial. Endlich kann man easy peasy eigene Datenpunkte anlegen und auch die fehlenden DeviceTypen anlegen. Sollte gleich mit in den Core aufgenommen werden, da fehlt sowas nämlich massiv.

            Ich habe grade mal ein paar States angelegt. Allerdings werden die Werte nicht weiter gegeben. Sowohl beim Zigbee Battery Percentage als auch bei Homematic ValveState or Boost State steht überall 0 drin.

            Muss man nach dem Einrichten der weiteren Alias States noch irgendwas machen?

            K s.bormann 2 Replies Last reply Reply Quote 0
            • K
              Kueppert @martinschm last edited by

              @martinschm zeig mal ein RAW. Da musst eigentlich nix machen. Hab den Adapter noch nicht benutzt. Hatte das vorher alles von Hand via Skript gemacht...
              ein Zigbee-Batterie-Alias von mir sieht zB so aus (inkl. Konvertierung zu true/false für das Batterie-Skript von DSLRaser):

              {
                "type": "state",
                "common": {
                  "name": "Abstellkammer Tür",
                  "role": "indicator.lowbat",
                  "type": "boolean",
                  "unit": "",
                  "desc": "Battery voltage",
                  "write": false,
                  "read": true,
                  "alias": {
                    "id": "zigbee.0.00158d0002753bd0.battery",
                    "read": "val < 15"
                  },
                  "states": {
                    "true": "leer",
                    "false": "voll"
                  },
                  "icon": "/icons/battery_v.png"
                },
                "native": {},
                "from": "system.adapter.javascript.0",
                "user": "system.user.admin",
                "ts": 1597147854822,
                "_id": "alias.0.Batterie.Abstellkammer_Tuer",
                "acl": {
                  "object": 1636,
                  "owner": "system.user.admin",
                  "ownerGroup": "system.group.administrator",
                  "state": 1636
                }
              }
              
              M 1 Reply Last reply Reply Quote 0
              • M
                martinschm @Kueppert last edited by

                @kueppert said in Test Adapter iQontrol 1.6.x Vis:

                @martinschm zeig mal ein RAW. Da musst eigentlich nix machen. Hab den Adapter noch nicht benutzt. Hatte das vorher alles von Hand via Skript gemacht...
                ein Zigbee-Batterie-Alias von mir sieht zB so aus (inkl. Konvertierung zu true/false für das Batterie-Skript von DSLRaser):

                {
                  "type": "state",
                  "common": {
                

                Hi,

                so sieht das bei mir aus

                {
                  "from": "system.adapter.admin.0",
                  "user": "system.user.admin",
                  "ts": 1615623246403,
                  "common": {
                    "name": "BatteryPercentage",
                    "type": "number",
                    "role": "value",
                    "unit": "%",
                    "read": true,
                    "write": true,
                    "alias": {
                      "id": "zigbee.0.00158d0004465ea3.battery",
                      "read": "",
                      "write": ""
                    }
                  },
                  "native": {},
                  "acl": {
                    "object": 1636,
                    "owner": "system.user.admin",
                    "ownerGroup": "system.group.administrator",
                    "state": 1636
                  },
                  "_id": "alias.0.Klimasensoren.Arbeitszimmer.BatteryPercentage",
                  "type": "state"
                }
                
                1 Reply Last reply Reply Quote 0
                • s.bormann
                  s.bormann Most Active @martinschm last edited by

                  @martinschm sagte in Test Adapter iQontrol 1.6.x Vis:

                  @s-bormann said in Test Adapter iQontrol 1.6.x Vis:

                  @kueppert sagte in Test Adapter iQontrol 1.6.x Vis:

                  @da_woody hab ich auch gemacht. War viel Arbeit, aber vereinfacht Skripte, VIS, iQontrol etc bei Gerätewechseln ungemein ^^ einfach im RAW den DP (das Gerät) anpassen, fertig

                  Ich habe auch viele Aliase angelegt. Aber mit dem aktuellen Devices-Adapter kam ich nicht so klar, deshalb habe ich die meisten "von Hand" angelegt. Dann musste ich einige Änderungen durchführen - und hätte alle Datenpunkte wieder von Hand anpacken müssen. Deshalb habe ich mir einen einfachen Adapter geschrieben, mit dem man Aliase einfacher bearbeiten kann. Vielleicht hilft es ja auch dem ein oder anderen:

                  https://github.com/sbormann/ioBroker.alias-manager

                  Alias-Manager

                  8b270fc8-a339-4785-8384-d331cc0ee8b4-image.png

                  Genial. Endlich kann man easy peasy eigene Datenpunkte anlegen und auch die fehlenden DeviceTypen anlegen. Sollte gleich mit in den Core aufgenommen werden, da fehlt sowas nämlich massiv.

                  Ich habe grade mal ein paar States angelegt. Allerdings werden die Werte nicht weiter gegeben. Sowohl beim Zigbee Battery Percentage als auch bei Homematic ValveState or Boost State steht überall 0 drin.

                  Muss man nach dem Einrichten der weiteren Alias States noch irgendwas machen?

                  War bei mir auch manchmal so - egal, ob die Aliase "von Hand" oder via Adpater angelegt wurden. Eine Aktualisierung des original-Datenpunktes oder ein ioBroker-Neustart hat Abhilfe gebracht.

                  1 Reply Last reply Reply Quote 1
                  • s.bormann
                    s.bormann Most Active @s.bormann last edited by

                    @s-bormann sagte in Test Adapter iQontrol 1.6.x Vis:

                    @kueppert sagte in Test Adapter iQontrol 1.6.x Vis:

                    Hallo in die Runde,
                    ich möchte gern einen User-DP manuell mit einer Zahl befüllen können. Wähle ich also Gerät "Wert" aus und verknüpfe "State" mit meinem User-Datenpunkt.
                    Hab auch mit dem Schraubenschlüssel was eingetragen:
                    3b65bced-dbdd-4bc4-8e1e-663d17f94e5d-image.png
                    Allerdings habe ich in iQontrol beim Klicken auf das Icon nur die Möglichkeit, den Wert 0-100 auszuwählen (der kann weg, ich brauche nur ein Eingabefeld) via Regler, keine Möglichkeit, selber einen Wert einzutragen.
                    753c08ba-aaae-4819-b2ee-80719010de9a-image.png
                    Ziel: Ich möchte über den User-DP meinen Stromzähler vom Haus loggen und den Wert via iQontrol schreiben können.

                    Jmd eine Idee, wie ich das bewerkstellige?

                    Hi,
                    versuch mal, o es geht, wenn man den Type von Nummer auf Zeichenfolge umstellt. Ist dann zwar eigentlich falsch - bringt aber ein Eingabefeld zu Tage 🙂

                    Hi,
                    habe das jetzt mal selbst getestet - und Du hast Recht:
                    Wenn der Wert des Datenpunktes eine Zahl ist und keine spezielle Rolle definiert ist, wird der Typ zu Zahl zurück-konvertiert. Habe das Verhalten jetzt mal in der aktuellen Github-Version geändert, so dass bei mir jetzt das Eingabefeld erscheint.

                    @all: Bitte ausführlich testen, ob das zu ungewünschten Seiteneffekten führt (d.h. konkret, ob alle Dialogfelder nach wie vor korrekt funktionieren - bei mir hat alles weiter wie gewohnt funktioniert, aber da es hier praktisch unendlich viele Kombinationsmöglichkeiten gibt, kann es schon sein, dass es in einigen Fällen zu Problemen kommt).

                    VG!

                    K 1 Reply Last reply Reply Quote 1
                    • s.bormann
                      s.bormann Most Active @da_Woody last edited by

                      @da_woody sagte in Test Adapter iQontrol 1.6.x Vis:

                      @s-bormann alder, das zeigst du jetzt erst??? peitsche.gif
                      gerade instet, mal guxxen, wie ich damit zurechtkomme... im RAW rumfummeln macht auch nicht gerade laune bei >80 geräten x menge DP... knud.gif

                      hmpf.

                      host.ioBroker	2021-03-12 20:44:23.873	error	system.adapter.alias-manager.0 invalid mode
                      

                      hmm, mode = "none", ist laut https://github.com/ioBroker/ioBroker.docs/blob/master/docs/en/dev/objectsschema.md#adapterinstance-commonmode auch erlaubt... Läuft der Adapter trotzdem?

                      1 Reply Last reply Reply Quote 0
                      • JLeg
                        JLeg last edited by

                        @s-bormann Dank Iqontrol habe ich nun auch endlich eine Visualisierung, die trotz völligen Talentmangels in Sachen "Layout" sogar von der besseren Hälfte akzeptiert wird - danke dafür! 🙂
                        Ein kleines Problem habe ich allerdings aktuell mit der Anzeige des DWD-Adapters (Wetter-Warnmeldungen) - ich bin mir sicher, dass das anfangs einwandfrei klappte, plötzlich jetzt aber nicht mehr. Ich benutze das Gerät "Popup", und habe in "additional_info" die Datenpunkte
                        dwd.0.warning.begin
                        dwd.0.warning.end

                        Während in den Objekten die Zeiten normal angezeigt werden

                        Fri Mar 12 2021 10:00:00 GMT+0100 (Mitteleuropäische Normalzeit)
                        

                        steht nun im Iqontrol Popup nur noch

                        Beginn: aN.aN.NaN, aN:aN
                        Ende: aN.aN.NaN, aN:aN
                        

                        Der Datentyp ist timestamp - und das offenbar "schon immer" (RAW: "ts": 1612643567563).
                        Ich dachte erst, ich könnte die Anzeige per "Schraubenschlüssel" korrigieren - dort gibt's aber nur "String", "Nummer" oder "Bool". Übersehe ich da was, oder geht das schlicht nicht (mehr)?

                        B s.bormann 2 Replies Last reply Reply Quote 0
                        • B
                          Beowolf @JLeg last edited by

                          @jleg sagte in Test Adapter iQontrol 1.6.x Vis:

                          in Sachen "Layout" sogar von der besseren Hälfte akzeptiert wird - danke dafür!

                          Jepp - kann ich bestätigen. Der "WAF" ist sehr hoch.👍

                          B 1 Reply Last reply Reply Quote 1
                          • B
                            Beowolf @Beowolf last edited by Beowolf

                            Habe da noch eine Frage.

                            Wie bekomme ich vor dem Datum einen Text. Datum ist ein Wert unter "INFO_A" im Gerätetyp "Info-Text".

                            "ist die nächste Leerung" ist unter "Array bearbeiten: INFO_A", dann Schraubenschlüssel, eingetragen unter "Einheit".

                            restm.jpg

                            Ich hätte gerne das der Text so aussieht "Am 17.02.2021 ist die nächste Leerung".

                            Geht das?

                            M da_Woody 2 Replies Last reply Reply Quote 0
                            • K
                              Kueppert @s.bormann last edited by Kueppert

                              @s-bormann funktioniert bei mir mit meinem Datenpunkt jetzt 😄 vielen Dank

                              NACHTRAG: Kommnando zurück...war mein TestDP, der eh schon auf Zeichenfolge stand. Bei dem anderen, der auf Number steht, gehts noch nicht. Hab von Git installiert, Versionsnummer hat sich nicht geändert. Muss ich einen anderen GIT-Link verwenden für die neue Version?

                              s.bormann 1 Reply Last reply Reply Quote 0
                              • M
                                martinschm @Beowolf last edited by

                                @beowolf said in Test Adapter iQontrol 1.6.x Vis:

                                Habe da noch eine Frage.

                                Wie bekomme ich vor dem Datum einen Text. Datum ist ein Wert unter "INFO_A" im Gerätetyp "Info-Text".

                                "ist die nächste Leerung" ist unter "Array bearbeiten: INFO_A", dann Schraubenschlüssel, eingetragen unter "Einheit".

                                restm.jpg

                                Ich hätte gerne das der Text so aussieht "Am 17.02.2021 ist die nächste Leerung".

                                Geht das?

                                Musst du dir wahrscheinlich als Text in einem Datenpunkt zusammenbauen und den Datenpunkt dann dort anzeigen.

                                1 Reply Last reply Reply Quote 0
                                • da_Woody
                                  da_Woody @Beowolf last edited by da_Woody

                                  @beowolf du könntest dir z.b. ein icon mit Am machen...
                                  Am.png <-- is ein .png
                                  schriftart latürnich dementsprechend...

                                  M 1 Reply Last reply Reply Quote 0
                                  • M
                                    martinschm @da_Woody last edited by

                                    @s-bormann mir ist bei deinem Alias Adapter ein kleiner Bug aufgefallen:

                                    cddfc07f-012d-4bed-80c2-15df36e96ca3-image.png

                                    s.bormann 1 Reply Last reply Reply Quote 0
                                    • F
                                      fredje @Kueppert last edited by

                                      @kueppert Hallo, habe mein Problem mit der Umwandlung number zu string immer noch nicht gelöst, irgentwie finde ich die Lösung nicht. Habe einen Alias angelegt mit dem Type string. Der Wert wird aber noch immer nicht richtig angezeigt. (Zahl mit Punkt). Muss ich im "alias read" Feld noch einen Javascript Befehl eintragen damit die Zahl in einen String umgewandelt wird.
                                      Danke für die Hilfe ...


                                      {
                                      "type": "state",
                                      "common": {
                                      "name": "Kennlinie",
                                      "type": "string",
                                      "role": "",
                                      "unit": "",
                                      "min": null,
                                      "max": null,
                                      "read": true,
                                      "write": true,
                                      "alias": {
                                      "id": "fhem.0.Broetje_HK1_OG.HK1_OGKennlinie",
                                      "read": "",
                                      "write": ""
                                      }
                                      },
                                      "_id": "alias.0.fhem.Broetje_HK1_OG.Kennlinie",
                                      "from": "system.adapter.admin.0",
                                      "user": "system.user.admin",
                                      "ts": 1615912202941,
                                      "acl": {
                                      "object": 1636,
                                      "state": 1636,
                                      "owner": "system.user.admin",
                                      "ownerGroup": "system.group.administrator"
                                      },
                                      "native": {}
                                      }

                                      K s.bormann 2 Replies Last reply Reply Quote 0
                                      • s.bormann
                                        s.bormann Most Active @martinschm last edited by

                                        @martinschm sagte in Test Adapter iQontrol 1.6.x Vis:

                                        @s-bormann mir ist bei deinem Alias Adapter ein kleiner Bug aufgefallen:

                                        cddfc07f-012d-4bed-80c2-15df36e96ca3-image.png

                                        Sehr aufmerksam! Wird korrigiert, danke!

                                        1 Reply Last reply Reply Quote 1
                                        • K
                                          Kueppert @fredje last edited by

                                          @fredje ich habe dafür das Skript von paul wie folgt angepasst:

                                          ///https://forum.iobroker.net/topic/27295/vorlage-alias-per-skript-erzeugen
                                          ///VAR-Konvertierung: https://forum.iobroker.net/topic/33747/alias-best-practices-wie-kann-man-es-besser-machen/39
                                          
                                          // Original-Datenpunkt
                                          const idOrigin = 'tankerkoenig.0.stations.3.diesel.feed'/*diesel feed*/;
                                          
                                           
                                          // Alias-Datenpunkt
                                          const idAlias = 'Spritpreise.JETDiesel';
                                          var typeAlias, read, write, nameAlias, role, desc, min, max, unit, states, custom;
                                          // Folgende kommentieren, wenn keine Änderung der Eigenschaft erforderlich
                                          nameAlias = 'JETDiesel';
                                          // desc = 'per Script erstellt';
                                          typeAlias = 'string'; // 'boolean' oder 'number' oder 'switch' oder 'state' oder 'string'
                                          read = "val.toFixed(2).replace('.',',')"; // Erkennung "Aus" --> false erfolgt automatisch  
                                          // write = "val ? 'Ein' : 'Aus'";
                                          // role = 'indicator.lowbat'; // 'switch.light' oder 'value.temperature' oder 'window.value' oder 'indicator.lowbat'
                                          // min = 0; // nur Zahlen
                                          // max = 100; // nur Zahlen
                                          unit = '€'; // nur für Zahlen, z.B. '%' oder '°C' oder ' ' wenn keine Unit!
                                          // states = {true: 'leer', false: 'voll'}; // Zahlen (Multistate) oder Logikwert (z.B. Aus/Ein)
                                          custom = {}; // verhindert doppelte Ausführung von history, telegram, mqtt-client, ...
                                           
                                          function createAlias(idSrc, idDst) {
                                             if(existsState(idDst)) log(idDst + ' schon vorhanden !', 'warn');
                                             else {
                                                var obj = {};
                                                obj.type = 'state';
                                                obj.common = getObject(idSrc).common;
                                                obj.common.alias = {};
                                                obj.common.alias.id = idSrc;
                                                if(typeAlias) obj.common.type = typeAlias;
                                                if(obj.common.read !== false && read) obj.common.alias.read = read;
                                                if(obj.common.write !== false && write) obj.common.alias.write = write;
                                                if(nameAlias) obj.common.name = nameAlias;
                                                if(role) obj.common.role = role;
                                                if(desc) obj.common.desc = desc;
                                                if(min !== undefined) obj.common.min = min;
                                                if(max !== undefined) obj.common.max = max;
                                                if(unit) obj.common.unit = unit;
                                                if(states) obj.common.states = states;
                                                if(custom && obj.common.custom) obj.common.custom = custom;
                                                if(obj.common.icon) delete obj.common.icon;
                                                obj.native = {};
                                                setObject(idDst, obj);
                                             } 
                                          }
                                           
                                          createAlias(idOrigin, 'alias.0.' + idAlias);
                                          
                                          F 1 Reply Last reply Reply Quote 0
                                          • s.bormann
                                            s.bormann Most Active @fredje last edited by

                                            @fredje sagte in Test Adapter iQontrol 1.6.x Vis:

                                            @kueppert Hallo, habe mein Problem mit der Umwandlung number zu string immer noch nicht gelöst, irgentwie finde ich die Lösung nicht. Habe einen Alias angelegt mit dem Type string. Der Wert wird aber noch immer nicht richtig angezeigt. (Zahl mit Punkt). Muss ich im "alias read" Feld noch einen Javascript Befehl eintragen damit die Zahl in einen String umgewandelt wird.
                                            Danke für die Hilfe ...


                                            {
                                            "type": "state",
                                            "common": {
                                            "name": "Kennlinie",
                                            "type": "string",
                                            "role": "",
                                            "unit": "",
                                            "min": null,
                                            "max": null,
                                            "read": true,
                                            "write": true,
                                            "alias": {
                                            "id": "fhem.0.Broetje_HK1_OG.HK1_OGKennlinie",
                                            "read": "",
                                            "write": ""
                                            }
                                            },
                                            "_id": "alias.0.fhem.Broetje_HK1_OG.Kennlinie",
                                            "from": "system.adapter.admin.0",
                                            "user": "system.user.admin",
                                            "ts": 1615912202941,
                                            "acl": {
                                            "object": 1636,
                                            "state": 1636,
                                            "owner": "system.user.admin",
                                            "ownerGroup": "system.group.administrator"
                                            },
                                            "native": {}
                                            }

                                            Habs nicht selbst getestet, aber versuch vielleicht mal bei alias.read val.toString() einzutragen, ggf. geht das dann?

                                            F 1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post

                                            Support us

                                            ioBroker
                                            Community Adapters
                                            Donate

                                            761
                                            Online

                                            31.6k
                                            Users

                                            79.4k
                                            Topics

                                            1.3m
                                            Posts

                                            app dark-mode iqontrol responsive vis visualisierung visualization widget
                                            295
                                            7633
                                            5431702
                                            Loading More Posts
                                            • Oldest to Newest
                                            • Newest to Oldest
                                            • Most Votes
                                            Reply
                                            • Reply as topic
                                            Log in to reply
                                            Community
                                            Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
                                            The ioBroker Community 2014-2023
                                            logo