{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "definitions": {
        "pushdataentry": {
            "type": "object",
            "title": "pushdataentry",
            "properties": {
                "url": {
                    "type": "string",
                    "description": "full URL of the middleware to push data to e.g. http://127.0.0.1/push/data.json"
                }
            },
            "required": [
                "url"
            ]
        },
        "local": {
            "type": "object",
            "properties": {
                "enabled": {
                    "type": "boolean",
                    "description": "should we start the local HTTPd for serving live readings?"
                },
                "port": {
                    "type": "integer",
                    "default": 8080,
                    "description": "the TCP port for the local HTTPd"
                },
                "index": {
                    "type": "boolean",
                    "description": "should we provide a index listing of available channels if no UUID was requested?"
                },
                "timeout": {
                    "type": "integer"
                },
                "buffer": {
                    "type": "integer"
                }
            },
            "required": [
                "enabled"
            ]
        },
        "channel": {
            "type": "object",
            "title": "channel",
            "properties": {
                "uuid": {
                    "type": "string",
                    "description": "uuid of this channel towards the middleware"
                },
                "identifier": {
                    "type": "string",
                    "description": "identifier of this channel from the meter. E.g. 1-0:1.8.0"
                },
                "api": {
                    "type": "string",
                    "enum": [
                        "volkszaehler",
                        "mysmartgrid",
                        "null"
                    ],
                    "default": "volkszaehler",
                    "description": "middleware api to be used. Defaults to volkszaehler.org"
                },
                "middleware": {
                    "type": "string",
                    "default": "http://localhost/middleware.php",
                    "description": "path/url to the api/middleware"
                },
                "secretKey": {
                    "type": "string",
                    "description": "secret key to use to talk to MySmartGrid api."
                },
                "type": {
                    "type": "string",
                    "enum": [
                        "device",
                        "sensor"
                    ],
                    "default": "device",
                    "description": "type of connected meter. Only needed for MySmartGrid api."
                },
                "scaler": {
                    "type": "integer",
                    "default": 1,
                    "description": "scaling factor to use. Only needed for MySmartGrid api."
                },
                "aggmode": {
                    "type": "string",
                    "enum": [
                        "avg",
                        "max",
                        "sum",
                        "none"
                    ],
                    "description": "Mittelwert fuer Leistung, MAX fuer Zaehler, SUM fuer Counter",
                    "default": "none"
                },
                "duplicates": {
                    "type": "integer",
                    "minimum": 0,
                    "default": 0,
                    "description": "default 0 (send duplicate values), >0 = send duplicate values only each <duplicates> seconds. Activate only for abs. counter values (Zaehlerstaende) and not for impulses!"
                }
            },
            "required": [
                "uuid",
                "identifier"
            ]
        },
        "meter": {
            "type": "object",
            "title": "meter",
            "properties": {
                "enabled": {
                    "type": "boolean",
                    "description": "enable or disable this meter. Disabled meter will be ignored.",
                    "default": false
                },
                "allowskip": {
                    "type": "boolean",
                    "description": "if enabled, errors when opening meter will lead to meter being ignored",
                    "default": false
                },
                "interval": {
                    "type": "integer",
                    "description": "delay in secs between queries to the meter",
                    "default": -1
                },
                "aggtime": {
                    "type": "integer",
                    "description": "aggregate all signals and give one update to middleware every <aggtime> seconds",
                    "default": -1
                },
                "aggfixedinterval": {
                    "type": "boolean",
                    "description": "round all timestamps to middleware to nearest aggtime",
                    "default": false
                },
                "channels": {
                    "$ref": "#/definitions/channels"
                }
            },
            "required": []
        },
        "meterInvalid": {
            "title": "invalid config for a meter. Choose any of the supported ones.",
            "allOf": [
                {
                    "$ref": "#/definitions/meter"
                },
                {
                    "properties": {
                        "protocol": {
                            "type": "string",
                            "enum": [
                                "invalid"
                            ]
                        }
                    }
                }
            ]
        },
        "meterS0": {
            "title": "S0 based meter",
            "allOf": [
                {
                    "$ref": "#/definitions/meter"
                },
                {
                    "properties": {
                        "protocol": {
                            "type": "string",
                            "enum": [
                                "s0"
                            ]
                        },
                        "device": {
                            "type": "string",
                            "description": "UART device the meter is connected to. E.g. /dev/ttyUSB0"
                        },
                        "gpio": {
                            "type": "integer",
                            "default": -1,
                            "description": "Number of GPIO port to be used. If this is set >-1 then device is ignored."
                        },
                        "mmap": {
                            "type": "string",
                            "default": "",
                            "description": "For gpio based devices and high frequency signals (>5-10kHz on a rpi2) memory mapped gpio can be used. Currently only supported on Raspberry-Pi 1 or 2. Leads to a constant but high CPU load depending on nonblocking_delay value. MMAPed GPIO pins need to be configured manually as input pins.",
                            "enum": [
                                "",
                                "rpi1",
                                "rpi2"
                            ]
                        },
                        "gpio_dir": {
                            "type": "integer",
                            "default": -1,
                            "description": "Number of GPIO port to be used as directional pin. If this pin is used and active Impulses_neg instead of Impulses is returned. Keep to -1 if unsure about the purpose."
                        },
                        "configureGPIO": {
                            "type": "boolean",
                            "default": true,
                            "description": "If true then vzlogger will export, configure,... the GPIO port. Needs proper access rights to /sys/class/gpio/."
                        },
                        "resolution": {
                            "type": "integer",
                            "default": 1000,
                            "description": "number of impulses per kWh"
                        },
                        "send_zero": {
                            "type": "boolean",
                            "default": false,
                            "description": "If active/true send data once a second even if no impulses have been received. Use aggregation is this case to reduce frequency."
                        },
                        "debounce_delay": {
                            "type": "integer",
                            "default": 30,
                            "description": "Delay in ms until the next edge is detected"
                        },
                        "nonblocking_delay": {
                            "type": "integer",
                            "default": 100000,
                            "description": "Delay in ns for polling/non-blocking interface. On an rpi2 e.g. 5000 can be used to detect up to 30kHz signals with mmap active."
                        }
                    },
                    "required": [
                        "protocol",
                        "device"
                    ]
                }
            ]
        },
        "meterD0": {
            "title": "D0 based meter",
            "allOf": [
                {
                    "$ref": "#/definitions/meter"
                },
                {
                    "properties": {
                        "protocol": {
                            "type": "string",
                            "enum": [
                                "d0"
                            ]
                        },
                        "device": {
                            "type": "string",
                            "description": "device the meter is connected to. E.g. /dev/ttyUSB0"
                        },
                        "host": {
                            "type": "string",
                            "description": "ip addr of the meter (if not directly connected)"
                        },
                        "dump_file": {
                            "type": "string",
                            "description": "path/filename of the file for the serial dump"
                        },
                        "pullseq": {
                            "type": "string",
                            "description": "sequence in hex to send to the meter before each read call. E.g. 2F3F210D0A"
                        },
                        "ackseq": {
                            "type": "string",
                            "description": "Reply sequence towards the meter. Should indicate the baud rate wanted. Will be send with initial baudrate. E.g. 063030300d0a for 300 baud. Use 'auto' to let vzlogger determine.",
                            "default": "auto"
                        },
                        "baudrate": {
                            "type": "integer",
                            "enum": [
                                50,
                                75,
                                110,
                                134,
                                150,
                                200,
                                300,
                                600,
                                1200,
                                1800,
                                2400,
                                4800,
                                9600,
                                19200,
                                38400,
                                57600,
                                115200,
                                230400
                            ],
                            "default": 300,
                            "description": "Baudrate to be used to for initial communication with the meter."
                        },
                        "baudrate_read": {
                            "type": "integer",
                            "enum": [
                                50,
                                75,
                                110,
                                134,
                                150,
                                200,
                                300,
                                600,
                                1200,
                                1800,
                                2400,
                                4800,
                                9600,
                                19200,
                                38400,
                                57600,
                                115200,
                                230400
                            ],
                            "default": 300,
                            "description": "Baudrate to be used after initial handshake (pullseq/answer/ackseq). Has to fit to ackseq. Will be determined automatically if ackseq 'auto' is used."
                        },
                        "parity": {
                            "type": "string",
                            "enum": [
                                "8n1",
                                "7n1",
                                "7e1",
                                "7o1"
                            ],
                            "default": "7e1",
                            "description": "parity used for serial communication"
                        },
                        "wait_sync": {
                            "type": "string",
                            "enum": [
                                "end",
                                "off"
                            ],
                            "default": "off",
                            "description": "Wait once for the sync pattern '!'. Intended for meters that start sending data automatically without pullseq."
                        },
                        "read_timeout": {
                            "type": "integer",
                            "default": 10,
                            "description": "Read timeout in secs. Data readout is considered finished if no state change after that timeout."
                        },
                        "baudrate_change_delay": {
                            "type": "integer",
                            "default": 0,
                            "description": "Delay in ms to apply before changing the baudrate. Defaults to 0 where tcdrain is used instead of a timeout."
                        }
                    }
                }
            ]
        },
        "meterSML": {
            "title": "SML based meter",
            "allOf": [
                {
                    "$ref": "#/definitions/meter"
                },
                {
                    "properties": {
                        "protocol": {
                            "type": "string",
                            "enum": [
                                "sml"
                            ]
                        },
                        "host": {
                            "type": "string",
                            "description": "ip addr of the meter (if not directly connected)"
                        },
                        "device": {
                            "type": "string",
                            "description": "device the meter is connected to. E.g. /dev/ttyUSB0"
                        },
                        "pullseq": {
                            "type": "string",
                            "description": "sequence in hex to send to the meter before each read call"
                        },
                        "baudrate": {
                            "type": "integer",
                            "enum": [
                                50,
                                75,
                                110,
                                134,
                                150,
                                200,
                                300,
                                600,
                                1200,
                                1800,
                                2400,
                                4800,
                                9600,
                                19200,
                                38400,
                                57600,
                                115200,
                                230400
                            ],
                            "default": 9600,
                            "description": "baudrate for serial communication"
                        },
                        "parity": {
                            "type": "string",
                            "enum": [
                                "8n1",
                                "7n1",
                                "7e1",
                                "7o1"
                            ],
                            "default": "8n1",
                            "description": "parity used for serial communication"
                        }
                    }
                }
            ]
        },
        "meterRandom": {
            "title": "example meter returning random values",
            "allOf": [
                {
                    "$ref": "#/definitions/meter"
                },
                {
                    "properties": {
                        "protocol": {
                            "type": "string",
                            "enum": [
                                "random"
                            ]
                        },
                        "min": {
                            "type": "number",
                            "description": "minimum value (floating point) that will be returned. E.g. 0.0"
                        },
                        "max": {
                            "type": "number",
                            "description": "maximum value (floating point) that will be returned. E.g. 10.0"
                        }
                    }
                }
            ]
        },
        "meterFile": {
            "title": "meter extracting data from a given file",
            "allOf": [
                {
                    "$ref": "#/definitions/meter"
                },
                {
                    "properties": {
                        "protocol": {
                            "type": "string",
                            "enum": [
                                "file"
                            ]
                        },
                        "path": {
                            "type": "string",
                            "description": "file incl. path to be used for data extraction"
                        },
                        "format": {
                            "type": "string",
                            "description": "optional format string. Supports $v for value, $i for identifier and $t for timestamp. E.g. $i:$v. If empty just a value is read from each line of the file."
                        },
                        "rewind": {
                            "type": "boolean",
                            "description": "rewind the file handle at each read?",
                            "default": false
                        }
                    },
                    "required": [
                        "path"
                    ]
                }
            ]
        },
        "meterExec": {
            "title": "meter extracting data from the output of a shell command/executable",
            "allOf": [
                {
                    "$ref": "#/definitions/meter"
                },
                {
                    "properties": {
                        "protocol": {
                            "type": "string",
                            "enum": [
                                "exec"
                            ]
                        },
                        "command": {
                            "type": "string",
                            "description": "Command to be executed. Only possible if running as non root. Output will be parsed."
                        },
                        "format": {
                            "type": "string",
                            "description": "optional format string. Supports $v for value, $i for identifier and $t for timestamp. E.g. $i:$v. If empty just a value is read from each line of the file."
                        }
                    },
                    "required": [
                        "command"
                    ]
                }
            ]
        },
        "meterFluksoV2": {
            "title": "fluksov2 meter",
            "allOf": [
                {
                    "$ref": "#/definitions/meter"
                },
                {
                    "properties": {
                        "protocol": {
                            "type": "string",
                            "enum": [
                                "fluksov2"
                            ]
                        },
                        "fifo": {
                            "type": "string",
                            "description": "fifo to be used.",
                            "default": "/var/run/spid/delta/out"
                        }
                    },
                    "required": [
                        "fifo"
                    ]
                }
            ]
        },
        "meterW1therm": {
            "title": "w1-therm / 1wire temperature sensors",
            "allOf": [
                {
                    "$ref": "#/definitions/meter"
                },
                {
                    "properties": {
                        "protocol": {
                            "type": "string",
                            "enum": [
                                "w1therm"
                            ]
                        }
                    }
                }
            ]
        },
        "meterOMS": {
            "title": "OMS / OMS (M-Bus) based devices",
            "allOf": [
                {
                    "$ref": "#/definitions/meter"
                },
                {
                    "properties": {
                        "protocol": {
                            "type": "string",
                            "enum": [
                                "oms"
                            ]
                        },
                        "device": {
                            "type": "string",
                            "description": "serial device the meter is connected to. E.g. /dev/ttyUSB0"
                        },
                        "baudrate": {
                            "type": "number",
                            "default": 9600,
                            "description": "Baudrate to use. Default to 9600."
                        },
                        "key": {
                            "type": "string",
                            "description": "AES key for the device in hex. Needs to be exactly 32 characters. E.g. 0102030405060708090a0b0c0d0e0f10"
                        },
                        "mbus_debug": {
                            "type": "boolean",
                            "default": false,
                            "description": "provide some more debug output on console by calling some libmbus debug functions"
                        }
                    },
                    "required": [
                        "device",
                        "key"
                    ]
                }
            ]
        },
        "meterOCRBB": {
            "type": "object",
            "properties": {
                "identifier": {
                    "type": "string",
                    "description": "id (obis-like) for this reading"
                },
                "scaler": {
                    "type": "integer",
                    "default": 0,
                    "description": "Scaling factor by 10^<scaler>. E.g. 0 = *1, -1 = *0.1, 2 = *100"
                },
                "digit": {
                    "type": "boolean",
                    "default": false,
                    "description": "a single digit is expected (thus the recognized value can only be within -9..9)"
                }
            }
        },
        "meterOCRBBInvalid": {
            "title": "invalid bounding-box. Choose any of the supported ones.",
            "allOf": [
                {
                    "$ref": "#/definitions/meterOCRBB"
                },
                {
                    "properties": {
                        "type": {
                            "type": "string",
                            "enum": [
                                "invalid"
                            ]
                        }
                    }
                }
            ]
        },
        "meterOCRBBCircle": {
            "title": "bounding-box with a circle",
            "allOf": [
                {
                    "$ref": "#/definitions/meterOCRBB"
                },
                {
                    "properties": {
                        "type": {
                            "type": "string",
                            "enum": [
                                "circle"
                            ]
                        },
                        "circle": {
                            "type": "object",
                            "properties": {
                                "cx": {
                                    "type": "integer",
                                    "description": "x coordinate of the center of the circle (top-left corner is (0,0))"
                                },
                                "cy": {
                                    "type": "integer",
                                    "description": "y coordinate of the center of the circle"
                                },
                                "cr": {
                                    "type": "integer",
                                    "default": 10,
                                    "description": "radius of the circle. 10 pixel minimum."
                                },
                                "offset": {
                                    "type": "number",
                                    "default": 0.0,
                                    "description": "offset of this needle. E.g. if at 5.0 (2nd digit needle at zero) but this needle show ~4.6 enter offset 0.4."
                                }
                            }
                        }
                    }
                }
            ]
        },
        "meterOCRBBBox": {
            "title": "bounding-box with a rectangle",
            "allOf": [
                {
                    "$ref": "#/definitions/meterOCRBB"
                },
                {
                    "properties": {
                        "type": {
                            "type": "string",
                            "enum": [
                                "box"
                            ]
                        },
                        "box": {
                            "type": "object",
                            "properties": {
                                "x1": {
                                    "type": "integer",
                                    "description": "left coordinate of the rectangle"
                                },
                                "y1": {
                                    "type": "integer",
                                    "description": "top coordinate of the rectangle"
                                },
                                "x2": {
                                    "type": "integer",
                                    "description": "right coordinate of the rectangle"
                                },
                                "y2": {
                                    "type": "integer",
                                    "description": "bottom coordinate of the rectangle"
                                }
                            }
                        }
                    }
                }
            ]
        },
        "meterOCRRecognizer": {
            "type": "object",
            "properties": {
                "boundingboxes": {
                    "oneOf": [
                        {
                            "$ref": "#/definitions/meterOCRBBInvalid"
                        },
                        {
                            "$ref": "#/definitions/meterOCRBBCircle"
                        },
                        {
                            "$ref": "#/definitions/meterOCRBBBox"
                        }
                    ]
                }
            }
        },
        "meterOCRRecognizerInvalid": {
            "title": "invalid recognizer. Choose any of the supported ones.",
            "allOf": [
                {
                    "$ref": "#/definitions/meterOCRRecognizer"
                },
                {
                    "properties": {
                        "type": {
                            "type": "string",
                            "enum": [
                                "invalid"
                            ]
                        }
                    }
                }
            ]
        },
        "meterOCRRecognizerNeedle": {
            "title": "needle type recognizer",
            "allOf": [
                {
                    "$ref": "#/definitions/meterOCRRecognizer"
                },
                {
                    "properties": {
                        "type": {
                            "type": "string",
                            "enum": [
                                "needle"
                            ]
                        },
                        "kernelColorString": {
                            "type": "string",
                            "description": "Color conversion 3x3 matrix. Default red channel only (2 -1 -1 0 0 0 0 0 0). First line channel red. Needles are detected for red color after matrix application. See leptonica:pixMultMatrixColor"
                        }
                    }
                }
            ]
        },
        "meterOCRRecognizerBinary": {
            "title": "binary (impulses) recognizer",
            "allOf": [
                {
                    "$ref": "#/definitions/meterOCRRecognizer"
                },
                {
                    "properties": {
                        "type": {
                            "type": "string",
                            "enum": [
                                "binary"
                            ]
                        },
                        "kernelColorString": {
                            "type": "string",
                            "description": "Color conversion 3x3 matrix. Default red channel only (2 -1 -1 0 0 0 0 0 0). First line channel red. Rectangle/pixes are detected for red color after matrix application. See leptonica:pixMultMatrixColor"
                        }
                    }
                }
            ]
        },
        "meterOCR": {
            "title": "meter extracting data from images (meterOCR)",
            "allOf": [
                {
                    "$ref": "#/definitions/meter"
                },
                {
                    "properties": {
                        "protocol": {
                            "type": "string",
                            "enum": [
                                "ocr"
                            ]
                        },
                        "impulses": {
                            "type": "integer",
                            "default": 0,
                            "description": "0 = report absolute values, >0 = report given impulses per unit"
                        },
                        "file": {
                            "type": "string",
                            "default": "/mnt/ramdisk/image.png",
                            "description": "filename of the image to be processed (or use v4l2_dev)"
                        },
                        "v4l2_dev": {
                            "type": "string",
                            "description": "v4l2 device name (e.g. /dev/video0). Keep empty if file based image should be used. Has preference over file."
                        },
                        "generate_debug_image": {
                            "type": "boolean",
                            "default": false,
                            "description": "generate debug images to ease configuration. Will be created in /run/vzlogger<nr>_debug.jpg for v4l2 or as <file>_debug.jpg if file based detection is used."
                        },
                        "rotate": {
                            "type": "number",
                            "default": 0.0,
                            "description": "angle in degree for rotation of the image. Positive angle turn clockwise."
                        },
                        "recognizer": {
                            "type": "array",
                            "items": {
                                "oneOf": [
                                    {
                                        "$ref": "#/definitions/meterOCRRecognizerInvalid"
                                    },
                                    {
                                        "$ref": "#/definitions/meterOCRRecognizerNeedle"
                                    },
                                    {
                                        "$ref": "#/definitions/meterOCRRecognizerBinary"
                                    }
                                ]
                            }
                        }
                    }
                }
            ]
        },
        "channels": {
            "type": "array",
            "items": {
                "oneOf": [
                    {
                        "$ref": "#/definitions/channel"
                    }
                ]
            }
        },
        "meters": {
            "type": "array",
            "minItems": 1,
            "items": {
                "oneOf": [
                    {
                        "$ref": "#/definitions/meterInvalid"
                    },
                    {
                        "$ref": "#/definitions/meterS0"
                    },
                    {
                        "$ref": "#/definitions/meterD0"
                    },
                    {
                        "$ref": "#/definitions/meterSML"
                    },
                    {
                        "$ref": "#/definitions/meterRandom"
                    },
                    {
                        "$ref": "#/definitions/meterFile"
                    },
                    {
                        "$ref": "#/definitions/meterExec"
                    },
                    {
                        "$ref": "#/definitions/meterFluksoV2"
                    },
                    {
                        "$ref": "#/definitions/meterOCR"
                    },
                    {
                        "$ref": "#/definitions/meterOMS"
                    },
                    {
                        "$ref": "#/definitions/meterW1therm"
                    }
                ]
            }
        },
        "push": {
            "type": "array",
            "minItems": 0,
            "items": {
                "oneOf": [
                    {
                        "$ref": "#/definitions/pushdataentry"
                    }
                ]
            },
            "description": "list of middlewares receiving push data (i.e. non aggregated live data in single http request)"
        }
    },
    "type": "object",
    "properties": {
        "retry": {
            "type": "integer",
            "description": "How long to sleep between failed requests, in seconds"
        },
        "daemon": {
            "type": "boolean",
            "default": "true",
            "description": "Enable daemon mode"
        },
        "verbosity": {
            "type": "integer",
            "enum": [
                0,
                5,
                10,
                15
            ],
            "description": "0 = log_error or log-warning, 5 = log_info, 10 = log-debug, 15 = log_finest",
            "default": 0
        },
        "log": {
            "type": "string",
            "description": "path to log file"
        },
        "push": {
            "$ref": "#/definitions/push"
        },
        "local": {
            "$ref": "#/definitions/local"
        },
        "meters": {
            "$ref": "#/definitions/meters"
        }
    },
    "required": [
        "daemon",
        "log"
    ]
}