InfluxDB

From Torben's Wiki

Install on Raspberry Pi in Raspbian

Nice Howto: [1]

wget -qO- https://repos.influxdata.com/influxdb.key | sudo apt-key add -
source /etc/os-release
test $VERSION_ID = "7" && echo "deb https://repos.influxdata.com/debian wheezy stable" | sudo tee /etc/apt/sources.list.d/influxdb.list
test $VERSION_ID = "8" && echo "deb https://repos.influxdata.com/debian jessie stable" | sudo tee /etc/apt/sources.list.d/influxdb.list
test $VERSION_ID = "9" && echo "deb https://repos.influxdata.com/debian stretch stable" | sudo tee /etc/apt/sources.list.d/influxdb.list
sudo apt-get install influxdb
sudo service influxdb restart

influxdb.conf

in /etc/influxdb/influxdb.conf

[http]
# Determines whether HTTP endpoint is enabled.
enabled = true
# require login of user
auth-enabled = true
# prevent logging of each HTTP request to reduce load on ssd
log-enabled = false

[logging]
level = "warn"

in ~/.bashrc

export INFLUX_USERNAME=admin
export INFLUX_PASSWORD=password1

Runs per default on port 8086

Administration

CLI: command line interface

sudo apt-get install influxdb-client
influx -precision rfc3339 # for human readable time format
# or 
influx
precision rfc3339

User permissions

user permissions are defined per database, so if you need only one level of permissions, one database might be enough

CREATE DATABASE raspi
USE raspi

suggestion: one user per permission

create user uadmin with password 'password1' WITH ALL PRIVILEGES
create user uwrite with password 'password2'
create user uread  with password 'password3'
grant read on raspi to uread
grant write on raspi to uwrite

Backup and Restore

influxd backup  -portable mypath
influxd restore -portable mypath

Renaming a Database via creating a copy of its tables

Attention: this will convert tags to fields is group by * missing

CREATE DATABASE mydb2
SELECT * INTO mydb2.autogen.table1 from mydb1.autogen.table1 group by *
DROP DATABASE mydb1

General commands

SHOW commands

SHOW DATABASES
SHOW MEASUREMENTS
SHOW RETENTION POLICIES
# display the field types of "table" myMeasurement
SHOW FIELD KEYS FROM myMeasurement
# show tags
SHOW TAG   KEYS FROM myMeasurement
# for example to be used in Grafana variables of type Query
SHOW TAG VALUES FROM myMeasurement WITH KEY =~ //
# CQ
SHOW CONTINUOUS QUERIES

SELECT statement

precision rfc3339
# for human readable timeformat
USE myDB
SELECT * FROM myMeasurement WHERE time > now() - 3d
SELECT * FROM myMeasurement WHERE myField > 12.2

# cast field into different type into new measurement
SELECT watt::float INTO myMeasurement2 FROM myMeasurement1

# copy into new measurement: 
SELECT watt::float, kWh_total_in::float, kWh_total_out::float INTO tasmota_MT681 FROM tmp
# use GROUP BY * to keep field types AND tags
SELECT watt_now, watt_last, kWh_total INTO tmp FROM Shelly GROUP BY *


Last value per day

SELECT last("kWh_total_in") as kWh_total_in, last("kWh_total_out") as kWh_total_out
FROM "tasmota_MT681"
WHERE 1=1
-- AND time > now() -2d
AND time < '2024-07-13T00:00:00+02:00'
GROUP BY time(1d) fill(previous)

DELETE alternative

DELETE is not supported in Influx V1

alternative:

# filter data into new tmp measurement and cast to float instead
# use GROUP BY * to keep field types and tags
SELECT watt::float, kWh_total_in, kWh_total_out INTO tmp FROM tasmota_MT681 WHERE kWh_total_in >0 GROUP BY *
# drop original measurement
DROP measurement tasmota_MT681
# restore from tmp
SELECT watt, kWh_total_in, kWh_total_out INTO tasmota_MT681 FROM tmp GROUP BY *
# cleanup
DROP MEASUREMENT tmp

Retention Policies

SHOW RETENTION POLICIES
# keep data for 10 years instead of 6 days (default)
CREATE RETENTION POLICY "years10" ON raspi DURATION 520w REPLICATION 1 DEFAULT
DROP   RETENTION POLICY "years10" ON raspi

# infinite 
CREATE RETENTION POLICY "inf" ON "raspi" DURATION INF REPLICATION 1

# if switching the default RETENTION POLICY old data will require a specific select
# altering the default RP:
ALTER RETENTION POLICY autogen ON raspi DURATION 90d SHARD DURATION 1d REPLICATION 1 DEFAULT
ALTER RETENTION POLICY autogen ON collectd DURATION 7d SHARD DURATION 1d REPLICATION 1 DEFAULT

Continuous Query / Auto aggregation

SHOW CONTINUOUS QUERIES

CREATE CONTINUOUS QUERY "cq_mt681_1d" ON "raspi" BEGIN \
 INTO "inf"."tasmota_MT681_day_end" \
 SELECT last("kWh_total_in") as kWh_total_in, last("kWh_total_out") as kWh_total_out \
 FROM "tasmota_MT681" \
GROUP BY time(1d) fill(previous) \
END

DROP CONTINUOUS QUERY "cq_mt681_1d" ON "raspi"

Connection via CURL

curl -G http://raspi3:8086/query -u uwrite:password2 --data-urlencode "q=SHOW DATABASES"

Insert via REST API and CURL

# precision=s (second) is important for performance, if higher accuracy is needed use ms, not ns which is the default!)
VALUE="123.123"
curl -i \
       -u uwrite:password2 \
       -XPOST "http://localhost:8086/write?db=raspi&precision=s" \
       --data-binary "myTable,myTag=SourceA myValue=$VALUE"

SELECT, INSERT and UPDATE via Python

SELECT into Pandas DataFrame

def read_data() -> pd.DataFrame:
    """Read data from Influx DB into DataFrame."""
    client = connect2_df(credentials_read)
    query = f'SELECT * FROM "{RETENTION}"."{MEASUREMENT}"'  # nosec  # noqa: S608
    result = client.query(query)
    df: pd.DataFrame = result[MEASUREMENT]  # type: ignore
    df.index.name = "time"
    client.close()
    return df

INSERT / UPDATE via Pandas DataFrame

def insert(df: pd.DataFrame) -> None:
    """Insert of df into Influx DB."""
    client = connect2_df(credentials_write)
    if len(df) > 0:
        client.write_points(
            df,
            MEASUREMENT,
            tag_columns=["room"],
            protocol="line",
            batch_size=1000,
            retention_policy=RETENTION,
            time_precision="s", # ns .. s
        )
    client.close()

INSERT JSON data via InfluxDBClient

see [2]

from influxdb import InfluxDBClient
client = InfluxDBClient(host='192.168.178.31', port=8086, username='write', password='password2 ')
# client.create_database('raspi')
print(client.get_list_database())
client.switch_database('raspi')

json = [
    {
        "measurement": "brushEvents",
        "tags": {
            "user": "Carol",
            "brushId": "6c89f539-71c6-490d-a28d-6c5d84c0ee2f"
        },
        "time": "2018-03-28T8:01:00Z",
        "fields": {
            "duration": 127
        }
    },
    {
        "measurement": "brushEvents",
        "tags": {
            "user": "Carol",
            "brushId": "6c89f539-71c6-490d-a28d-6c5d84c0ee2f"
        },
        "time": "2018-03-29T8:04:00Z",
        "fields": {
            "duration": 132
        }
    }
]

if client.write_points(json, time_precision="s") != True:
    print ("ERROR: Write to InfluxDB not successful")
else: 
    print ("data sent")