Giter Club home page Giter Club logo

home_assistant_hisense_tv's Introduction

Integrating a smart TV from Hisense on Home Assistant, using MQTT on your local network.

This is my successful experience getting this to work, with a TV Hisense H43B7320 and its firmware version V0000.01.00a.K0117.

Tested on Home Assistant Core version 0.111.4 and Mosquitto add-on version 5.1.

First of all, install the RemoteNow app on your android smartphone (https://play.google.com/store/apps/details?id=com.universal.remote.ms&hl=en). Pair the said smartphone with the TV, using the app. Save the mac address of this device for later.

You need to access the following path, having beforehand the Samba add-on installed on your Home Assistant instance:

  • Windows: \\YOUR_HA_LAN_IP\
  • Linux: smb://YOUR_HA_LAN_IP/

Put this inside a hisense.conf, in the above path - subfolder /share/mosquitto/. Change only the TV_IP_ADDRESS_CHANGE_IT_HERE, accordingly:

connection hisensemqtt
address TV_IP_ADDRESS_CHANGE_IT_HERE:36669
username hisenseservice
password multimqttservice
clientid HomeAssistant
bridge_cafile /ssl/hisense.crt
bridge_insecure true
bridge_tls_version tlsv1.2
try_private false
start_type automatic
topic +/remoteapp/# both

Inside the Mosquitto add-on configuration (previously installed, mandatory), in HA, change active from false to true:

customize:
  active: true
  folder: mosquitto

Run this command inside a linux terminal, to get the certificates needed to connect to the TVs embedded MQTT broker:

openssl s_client -host TV_IP_ADDRESS_CHANGE_IT_HERE -port 36669 -showcerts

Copy-paste inside the file /ssl/hisense.crt both certificates shown from the previous command, with this structure as an example:

-----BEGIN CERTIFICATE-----
qmierjfpaoisdjmçfaisldjcçfskdjafcaçskdjcçfmasidcf(...)
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
7ferusycedaystraedyasredyatrdsecdtrseydtraESYDTRASCY (...)
-----END CERTIFICATE-----

Inside the HA configuration.yaml file create these entries accordingly. Change here the smartphone mac address, previously saved by you, as stated (SMARTPHONE_MAC_ADDRESS_AUTHORIZED_PREVIOUSLY_WITH_THE_APP_REMOTENOW == AA:BB:CC:DD:EE:FF):

switch:
  - platform: template
    switches:
      hisense_tv:
        icon_template: >
          {% if is_state('switch.hisense_tv','on') %}
            {{ 'mdi:television-classic' }}
          {% else %}
            {{ 'mdi:television-classic-off' }}
          {% endif %}
        friendly_name: 'Hisense TV'
        value_template: >
          {{ is_state('device_tracker.hisense_tv', 'home') }}
        turn_on:
          service: wake_on_lan.send_magic_packet
          data:
            mac: 'TV_MAC_ADDRESS_CHANGE_IT_HERE'
        turn_off:
          service: mqtt.publish
          data:
            topic: '/remoteapp/tv/remote_service/SMARTPHONE_MAC_ADDRESS_AUTHORIZED_PREVIOUSLY_WITH_THE_APP_REMOTENOW$normal/actions/sendkey'
            payload: 'KEY_POWER'

wake_on_lan:

sensor:
  - platform: mqtt
    name: "TV - Source"
    state_topic: "/remoteapp/mobile/broadcast/ui_service/state"
    value_template: "{{ value_json.sourceid }}"

Inside the HA scripts.yaml file paste these scripts, useful later on to the lovelace card. Change here the smartphone mac address, previously saved by you, as stated (SMARTPHONE_MAC_ADDRESS_AUTHORIZED_PREVIOUSLY_WITH_THE_APP_REMOTENOW == AA:BB:CC:DD:EE:FF)

executa_hisense_input_tv:
  alias: TV - Input TV
  sequence:
    - service: mqtt.publish
      data:
        topic: '/remoteapp/tv/ui_service/SMARTPHONE_MAC_ADDRESS_AUTHORIZED_PREVIOUSLY_WITH_THE_APP_REMOTENOW$normal/actions/changesource'
        payload: '{"displayname":"TV","hotel_mode":"","isDemo":false,"is_lock":"","is_signal":"","sourceid":"0","sourcename":"TV"}'

executa_hisense_input_hdmi_1:
  alias: TV - Input HDMI 1
  sequence:
    - service: mqtt.publish
      data:
        topic: '/remoteapp/tv/ui_service/SMARTPHONE_MAC_ADDRESS_AUTHORIZED_PREVIOUSLY_WITH_THE_APP_REMOTENOW$normal/actions/changesource'
        payload: '{"displayname": "HDMI1","hotel_mode": "","isDemo": false,"is_lock": "","is_signal": "","sourceid": "4","sourcename": "HDMI1"}'

executa_hisense_input_hdmi_2:
  alias: TV - Input HDMI 2
  sequence:
    - service: mqtt.publish
      data:
        topic: '/remoteapp/tv/ui_service/SMARTPHONE_MAC_ADDRESS_AUTHORIZED_PREVIOUSLY_WITH_THE_APP_REMOTENOW$normal/actions/changesource'
        payload: '{"displayname": "HDMI2","hotel_mode": "","isDemo": false,"is_lock": "","is_signal": "","sourceid": "5","sourcename": "HDMI2"}'

executa_hisense_input_hdmi_3:
  alias: TV - Input HDMI 3
  sequence:
    - service: mqtt.publish
      data:
        topic: '/remoteapp/tv/ui_service/SMARTPHONE_MAC_ADDRESS_AUTHORIZED_PREVIOUSLY_WITH_THE_APP_REMOTENOW$normal/actions/changesource'
        payload: '{"displayname": "HDMI3","hotel_mode": "","isDemo": false,"is_lock": "","is_signal": "","sourceid": "6","sourcename": "HDMI3"}'

executa_hisense_volume_up:
  alias: TV - Volume up
  sequence:
    - service: mqtt.publish
      data:
        topic: '/remoteapp/tv/remote_service/SMARTPHONE_MAC_ADDRESS_AUTHORIZED_PREVIOUSLY_WITH_THE_APP_REMOTENOW$normal/actions/sendkey'
        payload: 'KEY_VOLUMEUP'
        
executa_hisense_volume_down:
  alias: TV - Volume down
  sequence:
    - service: mqtt.publish
      data:
        topic: '/remoteapp/tv/remote_service/SMARTPHONE_MAC_ADDRESS_AUTHORIZED_PREVIOUSLY_WITH_THE_APP_REMOTENOW$normal/actions/sendkey'
        payload: 'KEY_VOLUMEDOWN'

executa_hisense_channel_up:
  alias: TV - Channel up
  sequence:
    - service: mqtt.publish
      data:
        topic: '/remoteapp/tv/remote_service/SMARTPHONE_MAC_ADDRESS_AUTHORIZED_PREVIOUSLY_WITH_THE_APP_REMOTENOW$normal/actions/sendkey'
        payload: 'KEY_CHANNELUP'
        
executa_hisense_channel_down:
  alias: TV - Channel down
  sequence:
    - service: mqtt.publish
      data:
        topic: '/remoteapp/tv/remote_service/SMARTPHONE_MAC_ADDRESS_AUTHORIZED_PREVIOUSLY_WITH_THE_APP_REMOTENOW$normal/actions/sendkey'
        payload: 'KEY_CHANNELDOWN'

executa_hisense_home:
  alias: TV - Home
  sequence:
    - service: mqtt.publish
      data:
        topic: '/remoteapp/tv/remote_service/SMARTPHONE_MAC_ADDRESS_AUTHORIZED_PREVIOUSLY_WITH_THE_APP_REMOTENOW$normal/actions/sendkey'
        payload: 'KEY_HOME'

executa_hisense_netflix:
  alias: TV - Netflix
  sequence:
    - service: mqtt.publish
      data:
        topic: '/remoteapp/tv/ui_service/SMARTPHONE_MAC_ADDRESS_AUTHORIZED_PREVIOUSLY_WITH_THE_APP_REMOTENOW$normal/actions/launchapp'
        payload: '{"appIcon":"","appId":"1","has_detail_page":0,"isLocalApp":1,"name":"Netflix","storeType":0,"type":0,"url":"netflix","urlType":37}'

Create a manual lovelace card with this proposal:

cards:
  - cards:
      - type: horizontal-stack
        cards:
          - type: button
            tap_action:
              action: toggle
            hold_action:
              action: more-info
            show_icon: true
            show_name: true
            entity: switch.hisense_tv
            name: ON/OFF
          - type: entity
            entity: sensor.tv_source
            icon: 'mdi:video-input-hdmi'
      - cards:
          - entity: script.executa_hisense_input_tv
            hold_action:
              action: more-info
            show_icon: true
            show_name: true
            tap_action:
              action: toggle
            type: button
            name: TV
          - entity: script.executa_hisense_input_hdmi_1
            hold_action:
              action: more-info
            show_icon: true
            show_name: true
            tap_action:
              action: toggle
            type: button
            name: HDMI 1
          - entity: script.executa_hisense_input_hdmi_2
            hold_action:
              action: more-info
            show_icon: true
            show_name: true
            tap_action:
              action: toggle
            type: button
            name: HDMI 2
          - entity: script.executa_hisense_input_hdmi_3
            hold_action:
              action: more-info
            show_icon: true
            show_name: true
            tap_action:
              action: toggle
            type: button
            name: HDMI 3
        type: horizontal-stack
      - cards:
          - cards:
              - entity: script.executa_hisense_volume_up
                hold_action:
                  action: more-info
                show_icon: true
                show_name: true
                tap_action:
                  action: toggle
                type: button
                name: Volume UP
              - entity: script.executa_hisense_volume_down
                hold_action:
                  action: more-info
                show_icon: true
                show_name: true
                tap_action:
                  action: toggle
                type: button
                name: Volume DOWN
            type: vertical-stack
          - cards:
              - cards:
                  - entity: script.executa_hisense_channel_up
                    hold_action:
                      action: more-info
                    show_icon: true
                    show_name: true
                    tap_action:
                      action: toggle
                    type: button
                    name: Channel UP
                  - entity: script.executa_hisense_channel_down
                    hold_action:
                      action: more-info
                    show_icon: true
                    show_name: true
                    tap_action:
                      action: toggle
                    type: button
                    name: Channel DOWN
                type: vertical-stack
            type: vertical-stack
        type: horizontal-stack
      - cards:
          - entity: script.executa_hisense_netflix
            hold_action:
              action: more-info
            show_icon: true
            show_name: true
            tap_action:
              action: toggle
            type: button
            name: Netflix
          - entity: script.executa_hisense_home
            hold_action:
              action: more-info
            show_icon: true
            show_name: true
            tap_action:
              action: toggle
            type: button
            icon: 'mdi:menu'
            name: Menu
        type: horizontal-stack
    type: vertical-stack
type: vertical-stack

Customize these scripts with this proposal, inside the HA customize.yaml file:

script.executa_hisense_input_tv:
  icon: 'mdi:antenna'
  
script.executa_hisense_input_hdmi_1:
  icon: 'mdi:video-input-hdmi'
  
script.executa_hisense_input_hdmi_2:
  icon: 'mdi:video-input-hdmi'
  
script.executa_hisense_input_hdmi_3:
  icon: 'mdi:video-input-hdmi'

script.executa_hisense_netflix:
  icon: 'mdi:netflix'
  
script.executa_hisense_volume_up:
  icon: 'mdi:volume-plus'

script.executa_hisense_volume_down:
  icon: 'mdi:volume-minus'  

script.executa_hisense_channel_up:
  icon: 'mdi:arrow-up-drop-circle'
  
script.executa_hisense_channel_down:
  icon: 'mdi:arrow-down-drop-circle'
  
script.executa_hisense_home:
  icon: 'mdi:menu-open'

Will be similar to this:

lovelace_card

Further debugging or exploring the MQTT broker inside the TV

You may install the software MQTT Explorer (http://mqtt-explorer.com/) and use in your local network with these configurations:

mqtt_explorer_configs

If your can not stabilish a successful connection with the TV, first, try disabling the TLS encryption on the MQTT Explorer. Some older TVs or firmwares don't have encryption enabled. If so, you may need to change the above /share/mosquitto/hisense.conffile accordingly.

home_assistant_hisense_tv's People

Contributors

tiagofreire-pt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

home_assistant_hisense_tv's Issues

ha as an app on rasbian

Hi all, im trying to add my hisense r7 to my ha but i dont know how can i change this:
"
customize:
active: true
folder: mosquitto
"
where do i do this change if my mosquito is installed as an app as well?

i got already my cert, i added the scripts everythings, i see the script on my ha but once i clicked on everything of the template doesnt work.

I can see the commands on mqtt explorer but if i try to send a command doesnt really work (im not sure if i pubblish correctly)

Thanks

Can't get it to work properly

Hi there,

there seems to be something wrong with how the config of the MQTT Bridge is done. Everything works for me for approx. 2 minutes and I can control the TV during that time, but after that it doesn't work anymore and when I look into the log of my MQTT broker, it shows constant restarts (which are only there if I have the MQTT bridge to the Hisense TV defined):


Nov 05 14:58:40 homeassistant systemd[1]: mosquitto.service: Scheduled restart job, restart counter is at 68.
Nov 05 14:58:40 homeassistant systemd[1]: Stopped Mosquitto MQTT v3.1/v3.1.1 Broker.
Nov 05 14:58:40 homeassistant systemd[1]: Starting Mosquitto MQTT v3.1/v3.1.1 Broker...
Nov 05 14:58:40 homeassistant mosquitto[1183]: 1604584720: Loading config file /etc/mosquitto/conf.d/hisense.conf
Nov 05 14:58:40 homeassistant mosquitto[1183]: 1604584720: Warning: Bridge hisensemqtt using insecure mode.
Nov 05 14:58:40 homeassistant mosquitto[1183]: [397911.383058]~DLT~ 1183~INFO     ~FIFO /tmp/dlt cannot be opened. Retrying later...
Nov 05 14:58:40 homeassistant systemd[1]: Started Mosquitto MQTT v3.1/v3.1.1 Broker.
Nov 05 14:59:11 homeassistant systemd[1]: mosquitto.service: Main process exited, code=killed, status=11/SEGV
Nov 05 14:59:11 homeassistant systemd[1]: mosquitto.service: Failed with result 'signal'.
Nov 05 14:59:11 homeassistant systemd[1]: mosquitto.service: Scheduled restart job, restart counter is at 69.
Nov 05 14:59:11 homeassistant systemd[1]: Stopped Mosquitto MQTT v3.1/v3.1.1 Broker.
Nov 05 14:59:11 homeassistant systemd[1]: Starting Mosquitto MQTT v3.1/v3.1.1 Broker...
Nov 05 14:59:11 homeassistant mosquitto[1192]: 1604584751: Loading config file /etc/mosquitto/conf.d/hisense.conf
Nov 05 14:59:11 homeassistant mosquitto[1192]: 1604584751: Warning: Bridge hisensemqtt using insecure mode.
Nov 05 14:59:11 homeassistant mosquitto[1192]: [397942.882920]~DLT~ 1192~INFO     ~FIFO /tmp/dlt cannot be opened. Retrying later...
Nov 05 14:59:11 homeassistant systemd[1]: Started Mosquitto MQTT v3.1/v3.1.1 Broker.
Nov 05 14:59:43 homeassistant systemd[1]: mosquitto.service: Main process exited, code=killed, status=11/SEGV
Nov 05 14:59:43 homeassistant systemd[1]: mosquitto.service: Failed with result 'signal'.
Nov 05 14:59:43 homeassistant systemd[1]: mosquitto.service: Scheduled restart job, restart counter is at 70.
Nov 05 14:59:43 homeassistant systemd[1]: Stopped Mosquitto MQTT v3.1/v3.1.1 Broker.
Nov 05 14:59:43 homeassistant systemd[1]: Starting Mosquitto MQTT v3.1/v3.1.1 Broker...
Nov 05 14:59:43 homeassistant mosquitto[1201]: 1604584783: Loading config file /etc/mosquitto/conf.d/hisense.conf
Nov 05 14:59:43 homeassistant mosquitto[1201]: 1604584783: Warning: Bridge hisensemqtt using insecure mode.
Nov 05 14:59:43 homeassistant mosquitto[1201]: [397974.380772]~DLT~ 1201~INFO     ~FIFO /tmp/dlt cannot be opened. Retrying later...
Nov 05 14:59:43 homeassistant systemd[1]: Started Mosquitto MQTT v3.1/v3.1.1 Broker.

A closer look into /var/log/mosquitto shows the following:

1604586572: Connecting bridge (step 1) hisensemqtt (192.168.1.203:36669)
1604586572: Connecting bridge (step 2) hisensemqtt (192.168.1.203:36669)
1604586572: Error: Unable to load CA certificates, check bridge_cafile "/etc/mosquitto/conf.d/ca_certificates/hisense.crt".
1604586572: OpenSSL Error[0]: error:02001002:system library:fopen:No such file or directory
1604586572: OpenSSL Error[1]: error:2006D080:BIO routines:BIO_new_file:no such file
1604586572: OpenSSL Error[2]: error:0B084002:x509 certificate routines:X509_load_cert_crl_file:system lib

Apparently there is something wrong with my hisense.crt file. However, I created it according to your instructions and the file looks like this:


-----BEGIN CERTIFICATE-----
MIIDtDCCApygAwIBAgIBAj...
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
MIIDoTCCAomgAwIB..........
-----END CERTIFICATE-----

Here is my hisense.conf file:

connection hisensemqtt
address 192.168.1.203:36669
username hisenseservice
password multimqttservice
clientid HomeAssistant
bridge_cafile /etc/mosquitto/conf.d/ca_certificates/hisense.crt
bridge_insecure true
bridge_tls_version tlsv1.2
try_private false
start_type automatic
topic +/remoteapp/# both

Hmmmmm... I tried to manually verify the hisense.crt file and the output is ok:
openssl s_client -host 192.168.1.203 -port 36669 -CAfile ../ca_certificates/hisense.crt

CONNECTED(00000003)
Can't use SSL_get_servername
depth=1 C = CN, ST = shandong, L = qingdao, O = hh, OU = multimedia, CN = RemoteCA
verify return:1
depth=0 C = CN, ST = shandong, O = hh, OU = multiscreen, CN = 127.0.0.1
verify return:1
[...]
Server certificate
-----BEGIN CERTIFICATE-----
[...]
subject=C = CN, ST = shandong, O = hh, OU = multiscreen, CN = 127.0.0.1

issuer=C = CN, ST = shandong, L = qingdao, O = hh, OU = multimedia, CN = RemoteCA

---
No client certificate CA names sent
Peer signing digest: SHA512
Peer signature type: RSA
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 2558 bytes and written 409 bytes
Verification: OK
[...]

First Time HASSIO User Trying to Set this Up

Hi @tiagofreire-pt I am a first timer user of Hassio on a Raspberry Pi 3B, just to get my Hisense TV bridged over to Homekit; I am quite familiar with using Homebridge, but have never used Home Assistant before. I have followed the install guide and added my 'Filer Editor' addon, installed 'Mosquito Broker' addon, but am confused by the following step (maybe some assumed HAss knowledge that I am not familiar with):

'Put this inside a hisense.conf, in the Home Assistant Core (HA) folder /share/mosquitto/:'

In my File Editor Web UI, I cannot find a Home Assistant Core (HA) or share folder. Am I to create these folders? Should they already be there? Am I looking in the wrong place? Sorry for such simple questions but this just a platform I have no idea about.

Where exactly does this go in home assistant?

connection hisensemqtt
address TV_IP_ADDRESS_CHANGE_IT_HERE:36669
username hisenseservice
password multimqttservice
clientid HomeAssistant
bridge_cafile /ssl/hisense.crt
bridge_insecure true
bridge_tls_version tlsv1.2
try_private false
start_type automatic
topic +/remoteapp/# both

?

TV HISENSE 65U8GQ - Não funciona?

Olá,

Segui passo a passo as instruções e não consigo ligação do HA à minha TV HISENSE 65U8GQ.
No log do addon mosquitto broker posso ver o seguinte erro:
1672592712: Warning: Bridge hisensemqtt using insecure mode.
2023-01-01 17:05:12: Warning: Mosquitto should not be run as root/administrator.
[17:05:14] INFO: Successfully send discovery information to Home Assistant.
[17:05:15] INFO: Successfully send service information to the Supervisor.
2023-01-01 17:05:12: mosquitto version 2.0.11 starting
2023-01-01 17:05:12: Config loaded from /etc/mosquitto/mosquitto.conf.
2023-01-01 17:05:12: Loading plugin: /usr/share/mosquitto/go-auth.so
2023-01-01 17:05:12: ├── Username/password checking enabled.
2023-01-01 17:05:12: ├── TLS-PSK checking enabled.
2023-01-01 17:05:12: └── Extended authentication not enabled.
2023-01-01 17:05:12: Opening ipv4 listen socket on port 1883.
2023-01-01 17:05:12: Opening ipv6 listen socket on port 1883.
2023-01-01 17:05:12: Opening websockets listen socket on port 1884.
2023-01-01 17:05:12: Connecting bridge (step 1) hisensemqtt (192.168.33.25:36669)
2023-01-01 17:05:12: mosquitto version 2.0.11 running
2023-01-01 17:05:13: Connecting bridge (step 2) hisensemqtt (192.168.33.25:36669)
2023-01-01 17:05:13: OpenSSL Error[0]: error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
2023-01-01 17:05:13: Client local.HomeAssistant disconnected: Protocol error.

Os certificados foram retirados da própria TV com o comando openssl facultado e colocados conforme indicado no ficheiro /ssl/hisense.crt

O único erro ao seguir as instruções, além do resultado final, foi apenas no yaml do sensor:
sensor:

  • platform: mqtt 'missing property "device.id".'
    name: "TV - Source"
    state_topic: "/remoteapp/mobile/broadcast/ui_service/state"
    value_template: "{{ value_json.sourceid }}" 'Property value_template is not allowoed'

Mais informo que consigo ligação pelo MQTT Explorer à TV usando os certificados "genéricos" disponiveis aqui: https://github.com/d3nd3/Hisense-mqtt-keyfiles

Agradeço ajuda.
Obrigado

TV Source Unknown in Lovelace?Dashboard

My Hisense TV mode 65A6GTUK requires the rcm_certchain_pem.cer and rcm_pem_privkey.pkcs8 which I've added to hisense.conf as such;

connection hisensemqtt
address
username hisenseservice
password multimqttservice
clientid HomeAssistant
bridge_cafile /ssl/hisense.crt
bridge_insecure true
bridge_tls_version tlsv1.2
try_private false
start_type automatic
topic +/remoteapp/# both

I've followed all the steps but Lovelace tells me "TV Source Unkown"

Is this related perhaps to the "known_devices.yaml" I created in config but which is now depracated?

If so what should I do instead?

Lovelace screenshot

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.