Cybele icon indicating copy to clipboard operation
Cybele copied to clipboard

Glance Clock

Open anthonyangel opened this issue 3 years ago • 4 comments

Hi, does the Glance Clock integration work? If so then I'm happy to muddle through working out how to use it and writing up a Readme

anthonyangel avatar Jan 06 '21 11:01 anthonyangel

Hi!

Yep I've been using it for quite a while now. I wouldn't call it clean and it could definitely use more error handling but it has stood the test of time

Thank you!

To make this a bit easier, here's what I'm currently using to talk to the GlanceClock.

I hope that it will be at least somewhat helpful even though its's just unpolished copy paste

Click Me

Notify example from my home assistant configuration:

  - data:
      topic: "cybele/glanceclock/ffffffffff/notify"
    data_template:
      payload: >
          {
            "message": "{{ trigger.to_state.attributes.friendly_name }}: {{ trigger.to_state.state }}",
            "animation": "Wheel",
            "color": "RoyalBlue",
            "sound": "NoneSound",
            "repeatCount": 3
          }
    service: mqtt.publish

SetBrightness Example:

  - data:
      topic: "cybele/glanceclock/ffffffffff/setBrightness"
      payload_template: >
        {% if states.input_boolean.glance_clock_bad_bright.state == "on" %}
          {"value": "auto", "auto": {"min": 24, "max": 132}}
        {% else %}
          {"value": "auto", "auto": {"min": 1, "max": 24}}
        {% endif %}

saveForecastScene example taken from a node-red function node

const output = [];
const now = Math.round((Date.now() / 1000) - (new Date().getTimezoneOffset() *60));

const nowDate = new Date();

const temperatureScene = {
    timestamp: now,
    maxColor: "#FF0000",
    minColor: "#0000FF",
    max: 22, //wohlfühlbereich
    min: 6,
    template: [0xC2,0x8F,0x20,0x08,0xC2,0xB0],
    values: []
};

const temp = {
    min: null,
    max: null
}

const isNight = nowDate.getHours() >= 23 || nowDate.getHours() < 6 //used to not light up the room at night


Object.keys(msg.payload.temperature).forEach(k => {
    temp.min = temp.min ? Math.min(temp.min, msg.payload.temperature[k]) : msg.payload.temperature[k];
    temp.max = temp.max ? Math.max(temp.max, msg.payload.temperature[k]) : msg.payload.temperature[k];
    
    temperatureScene.values[parseInt(k)] = Math.round(msg.payload.temperature[k])
});


if(temp.max > 9 || temp.min < 0) {
    temperatureScene.template = temperatureScene.template.filter(e => e !== 0x20);
}

temperatureScene.min = Math.round(temp.min);
temperatureScene.max = Math.round(temp.max);


output.push({
    payload: {
        scene: temperatureScene,
        displayMode: isNight ? "text" : "both",
        sceneSlot: 1
    }
});


const precipationScene = {
    timestamp: now,
    maxColor: "#0000FF",
    minColor: "#000000",
    max: 1, //1mm in einer Stunde
    min: 0,
    template: [0xC2,0x95,0x20,0x08,0x6d,0x6d],
    values: []
};

const precip = {
    min: null,
    max: null
};


Object.keys(msg.payload.precipitation).forEach(k => {
    precip.min = precip.min ? Math.min(precip.min, msg.payload.precipitation[k]) : msg.payload.precipitation[k];
    precip.max = precip.max ? Math.max(precip.max, msg.payload.precipitation[k]) : msg.payload.precipitation[k];
    
    precipationScene.values[parseInt(k)] = Math.round(msg.payload.precipitation[k])
});

if(precip.max > 9) {
    precipationScene.template = precipationScene.template.filter(e => e !== 0x20);
}

precipationScene.min = Math.round(precip.min);
precipationScene.max = Math.round(precip.max) >= 1 ? Math.round(precip.max) : 1;



output.push({
    payload: {
        scene: precipationScene,
        displayMode: isNight ? "text" : "both",
        sceneSlot: 2
    }
});

function msToBeaufort(ms) {
    return Math.ceil(Math.cbrt(Math.pow(ms/0.836, 2)));
}

/*
const windScene = {
    timestamp: now,
    maxColor: "#00FF00",
    minColor: "#000000",
    max: 9, //Windstärke
    min: 0,
    template: [0xC2,0x98,0x20,0x08],
    values: []
};

const wind = {
    min: null,
    max: null
    
}


Object.keys(msg.payload.wind_speed).forEach(k => {
    wind.min = wind.min ? Math.min(wind.min, msg.payload.wind_speed[k]) : msg.payload.wind_speed[k];
    wind.max = wind.max ? Math.max(wind.max, msg.payload.wind_speed[k]) : msg.payload.wind_speed[k];
    
    windScene.values[parseInt(k)] = msToBeaufort(msg.payload.wind_speed[k])
});

if(wind.max > 9) {
    windScene.template = windScene.template.filter(e => e !== 0x20);
}

windScene.min = Math.round(wind.min);
windScene.max = Math.round(wind.max) >= 1 ? Math.round(wind.max) : 1;


output.push({
    payload: {
        scene: windScene,
        displayMode: "both",
        sceneSlot: 3
    }
});


const cloudsScene = {
    timestamp: now,
    maxColor: "#000000",
    minColor: "#FFFFFF",
    max: 100, //100% Wolkendecke
    min: 0,
    template: [0xC2,0x99,0x20,0x08,0x25],
    values: []
};

const clouds = {
    min: null,
    max: null
};


Object.keys(msg.payload.cloud_coverage).forEach(k => {
    clouds.min = clouds.min ? Math.min(clouds.min, msg.payload.cloud_coverage[k]) : msg.payload.cloud_coverage[k];
    clouds.max = clouds.max ? Math.max(clouds.max, msg.payload.cloud_coverage[k]) : msg.payload.cloud_coverage[k];
    
    cloudsScene.values[parseInt(k)] = Math.round(msg.payload.cloud_coverage[k])
});

if(clouds.max > 99) {
    cloudsScene.template = cloudsScene.template.filter(e => e !== 0x20);
}

cloudsScene.min = clouds.min;
cloudsScene.max = clouds.max >= 1 ? clouds.max : 1;



output.push({
    payload: {
        scene: cloudsScene,
        displayMode: "both",
        sceneSlot: 4
    }
});
*/



return [output];

SetTimer Payload Example:

{
            "intervals": [{
                "duration": totalTime
            }]
        }

StopTimer Payload:

{ "action": "stop"}

Hypfer avatar Jan 06 '21 11:01 Hypfer

Be advised that sometimes (I think it's caused by too many invalid requests/connection attempts) the clock looses its pairing information and needs to re-paired.

Unfortunately, this fails silently and can only be noticed by observing that data pushed to it doesn't appear anymore.

The pairing process is still rather tedious for some reason but has been at least mostly reproducible.

For best results, try turning bluetooth off and on again. That seems to help. Pairing looks more or less like this:

run bluetoothctl. In bluetoothctl do:

agent off
power off
power on
agent on
default-agent
menu scan
transport le
back
scan on

//The terminal will most likely be spammed by advertisements. Ignore that

<wait a few moments>
pair MAC_OF_YOUR_CLOCK
//enter pin displayed on the clock

//The clock should confirm pairing on its display. if not do "remove MAC_OF_YOUR_CLOCK" and try again from the start

Hypfer avatar Jan 06 '21 12:01 Hypfer

hi @Hypfer @anthonyangel !

First, thanks for the project !

i've just got the Glance Clock, run successfully the Cybele Project, but it doesn't start any action to my clock

my config.json:

{
  "mqtt": {
    "url": "mqtt://USER:PASS@MQTT_IP"
  },
  "dongles": [
    {
      "hciDevice": "hci0",
      "mode": "le",
      "services": [],
      "devices": [
        {
          "type": "GlanceClockDevice",
          "friendlyName": "GlanceClock_F3",
          "mac": "F1:95:1D:7F:D2:F3"
        }
      ]
    }
  ]
}

bluetoot is connected :

Agent registered
[CHG] Controller 00:1A:7D:DA:71:15 Pairable: yes
[GlanceClock_F3]# paired-devices
Device F1:95:1D:7F:D2:F3 GlanceClock_F3
[GlanceClock_F3]# info F1:95:1D:7F:D2:F3
Device F1:95:1D:7F:D2:F3 (random)
        Name: GlanceClock_F3
        Alias: GlanceClock_F3
        Appearance: 0x0100
        Paired: yes
        Trusted: yes
        Blocked: no
        Connected: yes
        LegacyPairing: no
        UUID: Generic Access Profile    (00001800-0000-1000-8000-00805f9b34fb)
        UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
        UUID: Device Information        (0000180a-0000-1000-8000-00805f9b34fb)
        UUID: Battery Service           (0000180f-0000-1000-8000-00805f9b34fb)
        UUID: Vendor specific           (5075f606-1e0e-11e7-93ae-92361f002671)
        UUID: Vendor specific           (8e400001-f315-4f60-9fb8-838830daea50)
        ManufacturerData Key: 0x004c
        ManufacturerData Value:
  02 15 50 75 f6 06 1e 0e 11 e7 93 ae 92 36 1f 00  ..Pu.........6..
  26 71 00 01 00 01 c3                             &q.....

The node app.js | grep "F1:95:1D does'nt show anything. I've tryied to publish to cybele/glanceclock/F1:95:1D:7F:D2:F3/notify but no effect, netiher on the log of app.js, neither on the clock

Could you help me please ? 🙏🏻

m4skime avatar Mar 25 '23 14:03 m4skime

find the solution !

the mac adress in the topic name must be in lowercase and without underscore

thanks again for the Cybele project ❤️

m4skime avatar Mar 25 '23 17:03 m4skime