Skip to content

Instantly share code, notes, and snippets.

@bitmorse
Created March 26, 2025 10:01
Show Gist options
  • Select an option

  • Save bitmorse/836b895d04aa44996f29bf9ec3e9c1f1 to your computer and use it in GitHub Desktop.

Select an option

Save bitmorse/836b895d04aa44996f29bf9ec3e9c1f1 to your computer and use it in GitHub Desktop.

Revisions

  1. bitmorse created this gist Mar 26, 2025.
    169 changes: 169 additions & 0 deletions iframe.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,169 @@
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="utf-8">
    <title>OpenWRT Load Monitor</title>
    <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
    <script crossorigin src="https://unpkg.com/@influxdata/giraffe"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <style>
    body {
    font-family: Arial, sans-serif;
    margin: 20px;
    }
    h1 {
    color: #333;
    }
    .loading {
    margin: 40px;
    font-size: 18px;
    color: #666;
    }
    .error {
    margin: 40px;
    font-size: 18px;
    color: #d32f2f;
    }
    </style>
    </head>

    <body>
    <h1>OpenWRT Load Monitor</h1>
    <main id="root"></main>
    <script type="text/javascript">
    class PlotRenderer extends React.Component {
    constructor(props) {
    super(props);
    this.state = {
    loading: true,
    error: null,
    fluxResponse: null
    };
    }

    componentDidMount() {
    this.fetchData();
    this.refreshInterval = setInterval(() => this.fetchData(), 60000);
    }

    componentWillUnmount() {
    if (this.refreshInterval) {
    clearInterval(this.refreshInterval);
    }
    }

    fetchData() {
    const url = 'YOUR INFLUX URL';
    const org = 'YOUR INFLUX ORG';
    const token = 'YOUR INFLUX RO TOKEN'; //READ ONLY!!!!!!

    const query = `
    from(bucket: "AVI")
    |> range(start: -24h)
    |> filter(fn: (r) => r._measurement == "openwrt_7628")
    |> filter(fn: (r) => r._field == "load")
    |> yield(name: "load")
    `;

    axios({
    method: 'POST',
    url: url,
    headers: {
    'Authorization': `Token ${token}`,
    'Content-Type': 'application/json',
    'Accept': 'application/csv'
    },
    params: {
    org
    },
    data: {
    query
    }
    })
    .then(response => {
    console.log("Data received:", response.data);

    // Add the missing headers that Giraffe expects
    const headers = [
    "#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string",
    "#group,false,false,true,true,false,false,true,true,true,true",
    "#default,_result,,,,,,,,,"
    ].join("\n");

    // Combine headers with the data
    const completeData = headers + "\n" + response.data;

    console.log("Complete data with headers:", completeData);

    this.setState({
    loading: false,
    fluxResponse: completeData
    });
    })
    .catch(error => {
    console.error("Error fetching data:", error);
    this.setState({
    loading: false,
    error: `Error fetching data: ${error.message}`
    });
    });
    }

    render() {
    const { loading, error, fluxResponse } = this.state;

    if (loading) {
    return React.createElement('div', { className: 'loading' }, 'Loading data...');
    }

    if (error) {
    return React.createElement('div', { className: 'error' }, error);
    }

    const style = {
    width: "calc(70vw - 20px)",
    height: "calc(70vh - 20px)",
    margin: "40px",
    };

    // If we have data, create a plot with it
    if (fluxResponse) {
    try {
    // Create a simple line layer
    const lineLayer = {
    type: "line",
    x: "_time",
    y: "_value",
    colors: ["#31C0F6"],
    lineWidth: 2
    };

    // Create the config using the fluxResponse with added headers
    const config = {
    fluxResponse,
    layers: [lineLayer]
    };

    // Create the Plot component
    const Plot = React.createElement(Giraffe.Plot, {config}, null);
    return React.createElement('div', {style}, Plot);
    } catch (e) {
    console.error("Error creating plot:", e);
    return React.createElement('div', { className: 'error' },
    `Error creating plot: ${e.message}. Check console for details.`);
    }
    }

    return React.createElement('div', null, 'No data available');
    }
    }

    // Render the component
    ReactDOM.render(
    React.createElement(PlotRenderer),
    document.getElementById('root')
    );
    </script>
    </body>
    </html>