Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Glance Clock #12

Open
anthonyangel opened this issue Jan 6, 2021 · 4 comments
Open

Glance Clock #12

anthonyangel opened this issue Jan 6, 2021 · 4 comments

Comments

@anthonyangel
Copy link

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

@Hypfer
Copy link
Owner

Hypfer commented Jan 6, 2021

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
Copy link
Owner

Hypfer commented Jan 6, 2021

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

@m4skime
Copy link

m4skime commented Mar 25, 2023

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
Copy link

m4skime commented Mar 25, 2023

find the solution !

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

thanks again for the Cybele project ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants