Jump to content

Recommended Posts

Posted
15 minutes ago, Pocster said:

Perhaps don’t give it your script , get it to write it from scratch? - see what you get then .

 

8 hours ago, S2D2 said:

Given no context, it produces code that looks fine. It doesn't even vaguely work as it gets the API syntax (which is publicly documented) very wrong. Fixing it requires replacing many lines of code

 

Posted (edited)

@S2D2 as an experiment. Post here your exact textual requirements. I stick it in chat and I’ll post the result . I’ve no idea what you are trying to do - so you’ll have to judge the output assuming it differs to what you have .

Edited by Pocster
Posted

The other thing I do is plug the output ( compile errors / syntax errors ) back into chat . I’ve had it get syntax wrong or take a few attempts to get a certain thing right . Lots of copy n paste for me .

Posted
44 minutes ago, Pocster said:

@S2D2 as an experiment. Post here your exact textual requirements. I stick it in chat and I’ll post the result . I’ve no idea what you are trying to do - so you’ll have to judge the output assuming it differs to what you have .

This is no longer possible as it has seen my working code and will now produce a working example - you're welcome ChatGPT!

 

Previously it accessed into JSON data using an invalid key and tried to store cumulative data as hourly totals (PV forecast from forecast.solar). The former is easy to spot, an outright error. The latter will look like it has worked but the values are nonsense, much more dangerous.

 

I appreciate I'm being overly negative, it's a useful tool for getting started or finding relevant information but a lot of care is needed when using the output code.

  • Like 1
Posted
Just now, S2D2 said:

This is no longer possible as it has seen my working code and will now produce a working example - you're welcome ChatGPT!

 

Previously it accessed into JSON data using an invalid key and tried to store cumulative data as hourly totals (PV forecast from forecast.solar). The former is easy to spot, an outright error. The latter will look like it has worked but the values are nonsense, much more dangerous.

 

I appreciate I'm being overly negative, it's a useful tool for getting started or finding relevant information but a lot of care is needed when using the output code.

Not something else you need doing ?

i.e you ask it - get its generated code . Tell me the exact same thing ; I ask ‘my’ chat .

Be interesting too see 

a- if yours works 

b- if your version and my version are the same 

 

Only if you’ve got time of course !

Posted
21 minutes ago, S2D2 said:

This is no longer possible as it has seen my working code and will now produce a working example - you're welcome ChatGPT!

That’s not correct . You are sandboxed . Your code exists just in that chat session , it’s not on a public server somewhere .

Also chats ‘knowledge ‘ is 2 yrs old 

Close your chat . Open a new session - ask your same question - see what you get .

 

I was frustrated when it hit my gpio pins wrong and I searched and sorted it . If asked it why ? . It said there are many versions of the same board from China ( I know this to be true even if the model number is identical ) and it choose the ‘most likely ‘ configuration.

Posted

 

23 minutes ago, Pocster said:

Not something else you need doing ?

i.e you ask it - get its generated code . Tell me the exact same thing ; I ask ‘my’ chat .

Be interesting too see 

a- if yours works 

b- if your version and my version are the same 

 

Only if you’ve got time of course !

Quote

Write a Python script to calculate the size of walk on glazing to order given a measured opening.

Quote

def calculate_glass_size(opening_width, opening_length, tolerance=10):
    """
    Calculates the glass size to order for walk-on glazing.

    Args:
        opening_width (float): Width of the measured opening (in mm).
        opening_length (float): Length of the measured opening (in mm).
        tolerance (float): Gap to subtract on each side (in mm). Default is 10 mm.

    Returns:
        (glass_width, glass_length): Tuple with dimensions of the glass to order (in mm).
    """
    glass_width = opening_width - (2 * tolerance)
    glass_length = opening_length - (2 * tolerance)

    return round(glass_width, 1), round(glass_length, 1)


def main():
    print("Walk-On Glazing Size Calculator\n")

    try:
        opening_width = float(input("Enter the measured opening WIDTH (in mm): "))
        opening_length = float(input("Enter the measured opening LENGTH (in mm): "))
        tolerance_input = input("Enter tolerance per side (mm, press Enter for default 10mm): ")

        tolerance = float(tolerance_input) if tolerance_input.strip() != "" else 10.0

        glass_width, glass_length = calculate_glass_size(opening_width, opening_length, tolerance)

        print("\n📏 Glass Size to Order:")
        print(f"➡️ Width:  {glass_width} mm")
        print(f"➡️ Length: {glass_length} mm")
        print(f"(Tolerance per side: {tolerance} mm)")

    except ValueError:
        print(" Invalid input. Please enter numeric values only.")


if __name__ == "__main__":
    main()

Apologies for the formatting and you'll have to sanity check the output for me!

Posted
2 minutes ago, S2D2 said:

 

Apologies for the formatting and you'll have to sanity check the output for me!

Well I’m not a python expert but I suspect that will compile and work .

So anything unique that you need doing ? Custom ?

Posted
1 hour ago, Pocster said:

That’s not correct . You are sandboxed . Your code exists just in that chat session , it’s not on a public server somewhere .

Also chats ‘knowledge ‘ is 2 yrs old 

I disagree, but I didn't use the exact same prompt so it could be pure coincidence.

1 hour ago, Pocster said:

anything unique that you need doing ? Custom ?

Not that comes to mind and I'm not logged in, so you could see what I do with a logged out session.

Posted
1 hour ago, Pocster said:

That’s not correct . You are sandboxed . Your code exists just in that chat session , it’s not on a public server somewhere .

Careful with that. Peoples interactions with AI keep popping up in search engine results unintentionally. Most AI companies are using user interactions as training for future models (some in more limited ways than others). In general you will have control over this but dark patterns seem to be causing leaks when users expect privacy.

 

1 hour ago, Pocster said:

Also chats ‘knowledge ‘ is 2 yrs old 

 

Less than that these days. Many of the 'pro' models will happily go out and search the live internet for you (at a cost in more tokens).

  • Like 2
Posted
7 minutes ago, S2D2 said:

I disagree, but I didn't use the exact same prompt so it could be pure coincidence.

😊 it doesn’t stire e frothing everyone says !!! Where’s your super code stored ? . Probably billions of code fragments a day !

Tell me your original textual request where it produced the crap code . I’ll enter the same. I’ll either get the crap code or your magic version !

Posted
3 minutes ago, -rick- said:

Careful with that. Peoples interactions with AI keep popping up in search engine results unintentionally.

Yes - this is bound to happen so some extent . But I think @S2D2 would be a good test / example . Sure we are all being data harvested . But exactly what gets stored who knows . 

Posted
32 minutes ago, Pocster said:

Tell me your original textual request where it produced the crap code . I’ll enter the same. I’ll either get the crap code or your magic version !

Dunno, the original prompt is gone.

 

Here's one that spits out non-functioning code:

Quote

Create a Python script which fetches hourly entries from the forecast.solar api in utc time and saves them to an influxdb instance.

 

Here's some info on data collection: https://help.openai.com/en/articles/5722486-how-your-data-is-used-to-improve-model-performance

  • Like 1
Posted
7 minutes ago, S2D2 said:

Dunno, the original prompt is gone.

 

Here's one that spits out non-functioning code:

 

Here's some info on data collection: https://help.openai.com/en/articles/5722486-how-your-data-is-used-to-improve-model-performance

Here what I get 

 

#!/usr/bin/env python3
"""
Fetch hourly forecast.solar data (UTC) and write to InfluxDB 2.x.

It writes one point per timestamp with fields:
  - watts          (instantaneous power W)
  - watt_hours     (cumulative Wh)
  - watt_hours_day (daily Wh; only on YYYY-MM-DD entries)

Tags include: site, lat, lon, azimuth, declination, kwp, source="forecast.solar".

Configuration is via environment variables (see below).
"""

import os
import sys
import time
import json
import math
from datetime import datetime, timezone

import requests
from influxdb_client import InfluxDBClient, Point, WriteOptions

# ----------------------------
# Configuration (env vars)
# ----------------------------
FS_API_KEY   = os.getenv("FS_API_KEY", "").strip()     # optional; public API works without a key (1 hr resolution, today+tomorrow)
FS_LAT       = os.getenv("FS_LAT")                     # required
FS_LON       = os.getenv("FS_LON")                     # required
FS_DECL      = os.getenv("FS_DECL")                    # panel tilt / declination in degrees (e.g. 37)
FS_AZIMUTH   = os.getenv("FS_AZIMUTH")                 # 0 = south, 90 = west, 180 = north, 270 = east (Forecast.Solar uses 0=south)
FS_KWP       = os.getenv("FS_KWP")                     # system size in kWp (e.g. 4.2)

# InfluxDB 2.x
INFLUX_URL   = os.getenv("INFLUX_URL", "http://localhost:8086")
INFLUX_TOKEN = os.getenv("INFLUX_TOKEN")               # required
INFLUX_ORG   = os.getenv("INFLUX_ORG", "primary")      # required-ish
INFLUX_BUCKET= os.getenv("INFLUX_BUCKET", "solar")     # required-ish

# Optional niceties
SITE_TAG     = os.getenv("SITE_TAG", "home")           # tag to identify the site
MEASUREMENT  = os.getenv("MEASUREMENT", "solar_forecast")
USER_AGENT   = os.getenv("USER_AGENT", "forecast-solar-influx/1.0")

# Timeout & retry
HTTP_TIMEOUT = float(os.getenv("HTTP_TIMEOUT", "10"))
RETRIES      = int(os.getenv("RETRIES", "2"))
BACKOFF_S    = float(os.getenv("BACKOFF_S", "1.5"))

def _env_must(name):
    v = os.getenv(name)
    if not v:
        sys.stderr.write(f"Missing env var: {name}\n")
        sys.exit(2)
    return v

def _validate_inputs():
    # Required numeric params
    for name in ("FS_LAT","FS_LON","FS_DECL","FS_AZIMUTH","FS_KWP"):
        _ = _env_must(name)

    # Influx 2.x requirements
    _env_must("INFLUX_TOKEN")
    # org & bucket can default, but ensure not empty
    if not INFLUX_ORG:
        sys.stderr.write("INFLUX_ORG is empty\n"); sys.exit(2)
    if not INFLUX_BUCKET:
        sys.stderr.write("INFLUX_BUCKET is empty\n"); sys.exit(2)

def build_api_url():
    """
    Forecast.Solar format:
      https://api.forecast.solar/[API_KEY/]<route>/<lat>/<lon>/<decl>/<azimuth>/<kwp>?time=utc

    Public (no key) is allowed with hourly resolution (today+tomorrow).
    We explicitly request UTC timestamps.
    """
    base = "https://api.forecast.solar"
    route = "estimate"
    path = f"{float(FS_LAT):.6f}/{float(FS_LON):.6f}/{int(float(FS_DECL))}/{int(float(FS_AZIMUTH))}/{float(FS_KWP):.3f}"

    if FS_API_KEY:
        url = f"{base}/{FS_API_KEY}/{route}/{path}"
    else:
        url = f"{base}/{route}/{path}"

    # force UTC timestamps
    return f"{url}?time=utc"

def http_get_json(url):
    headers = {"User-Agent": USER_AGENT, "Accept": "application/json"}
    last_err = None
    for attempt in range(1, RETRIES+2):
        try:
            r = requests.get(url, headers=headers, timeout=HTTP_TIMEOUT)
            if r.status_code == 429:
                # rate limited: back off a bit
                time.sleep(BACKOFF_S * attempt)
                continue
            r.raise_for_status()
            return r.json()
        except Exception as e:
            last_err = e
            time.sleep(BACKOFF_S * attempt)
    raise RuntimeError(f"Failed to GET {url}: {last_err}")

def parse_timeseries(result_obj):
    """
    result_obj looks like:
      {
        "watts": {
          "2019-06-22 05:00:00": 0, ...
        },
        "watt_hours": { ... cumulative ... },
        "watt_hours_day": { "2019-06-22": 2626, ... }
      }
    Timestamps are strings in 'YYYY-MM-DD HH:MM:SS' and (with ?time=utc) are in UTC.

    Returns list of dicts:
      {"ts": datetime(UTC), "watts": int, "watt_hours": int}
    And a dict for day totals keyed by YYYY-MM-DD.
    """
    watts = result_obj.get("watts", {}) or {}
    wh    = result_obj.get("watt_hours", {}) or {}
    wh_day= result_obj.get("watt_hours_day", {}) or {}

    rows = []
    for ts_str, w in watts.items():
        # e.g. "2019-06-22 05:00:00"
        dt = datetime.strptime(ts_str, "%Y-%m-%d %H:%M:%S").replace(tzinfo=timezone.utc)
        rows.append({
            "ts": dt,
            "watts": int(w) if w is not None else None,
            "watt_hours": int(wh.get(ts_str)) if ts_str in wh and wh.get(ts_str) is not None else None
        })

    # Sort by time just in case
    rows.sort(key=lambda r: r["ts"])
    return rows, wh_day

def write_points_influx(rows, day_totals):
    client = InfluxDBClient(url=INFLUX_URL, token=INFLUX_TOKEN, org=INFLUX_ORG)
    write = client.write_api(write_options=WriteOptions(batch_size=500, flush_interval=5_000))

    # Static tags
    base_tags = {
        "site": SITE_TAG,
        "lat": f"{float(FS_LAT):.6f}",
        "lon": f"{float(FS_LON):.6f}",
        "declination": str(int(float(FS_DECL))),
        "azimuth": str(int(float(FS_AZIMUTH))),
        "kwp": f"{float(FS_KWP):.3f}",
        "source": "forecast.solar"
    }

    points = []

    for r in rows:
        p = (
            Point(MEASUREMENT)
            .tag("site", base_tags["site"])
            .tag("lat", base_tags["lat"])
            .tag("lon", base_tags["lon"])
            .tag("declination", base_tags["declination"])
            .tag("azimuth", base_tags["azimuth"])
            .tag("kwp", base_tags["kwp"])
            .tag("source", base_tags["source"])
            .time(r["ts"])
        )
        if r["watts"] is not None:
            p = p.field("watts", int(r["watts"]))
        if r["watt_hours"] is not None:
            p = p.field("watt_hours", int(r["watt_hours"]))
        points.append(p)

    # Also write day totals as separate points (same measurement) with a "day_total" field
    for day_str, val in day_totals.items():
        try:
            dt = datetime.strptime(day_str, "%Y-%m-%d").replace(tzinfo=timezone.utc)
        except Exception:
            continue
        p = (
            Point(MEASUREMENT)
            .tag("site", base_tags["site"])
            .tag("lat", base_tags["lat"])
            .tag("lon", base_tags["lon"])
            .tag("declination", base_tags["declination"])
            .tag("azimuth", base_tags["azimuth"])
            .tag("kwp", base_tags["kwp"])
            .tag("source", base_tags["source"])
            .time(dt)
            .field("watt_hours_day", int(val))
        )
        points.append(p)

    if points:
        write.write(bucket=INFLUX_BUCKET, org=INFLUX_ORG, record=points)
    write.close()
    client.close()

def main():
    _validate_inputs()
    url = build_api_url()
    data = http_get_json(url)

    # Forecast.Solar wraps the payload as {"result": {...}, "message": {...}}
    result = (data or {}).get("result")
    if not result:
        msg = (data or {}).get("message", {})
        raise SystemExit(f"No 'result' in response. message={msg}")

    rows, day_totals = parse_timeseries(result)
    if not rows and not day_totals:
        raise SystemExit("No data parsed from API response.")
    write_points_influx(rows, day_totals)
    print(f"Wrote {len(rows)} hourly points and {len(day_totals)} day totals to InfluxDB bucket '{INFLUX_BUCKET}'.")

if __name__ == "__main__":
    main()

 

Install 

python3 -m venv .venv
. .venv/bin/activate
pip install requests influxdb-client

 

Export config example 

export FS_LAT=51.5074
export FS_LON=-0.1278
export FS_DECL=37
export FS_AZIMUTH=0
export FS_KWP=4.2
# optional key if you have a paid plan; omit for public endpoint
# export FS_API_KEY=your_api_key

export INFLUX_URL=http://localhost:8086
export INFLUX_TOKEN=YOUR_INFLUXDB_TOKEN
export INFLUX_ORG=your_org
export INFLUX_BUCKET=solar
export SITE_TAG=roof

 

Run it

python forecast_solar_to_influx.py

 

Schedule it with cron/systemd to run hourly (public API updates hourly; paid tiers can be finer).

 

 

 

 

Measurement & schema

 

 

  • measurement: solar_forecast (override with MEASUREMENT)
  • tags: site, lat, lon, declination, azimuth, kwp, source=forecast.solar
  • fields:
    • watts (int)
    • watt_hours (int; cumulative)
    • watt_hours_day (int; only on daily points)
  •  

 

 

All timestamps are written as UTC. The script requests ?time=utc and treats incoming timestamps as UTC when parsing.

 

 

 

 

Notes / gotchas

 

 

  • Public vs API key: Public endpoint (no key) returns hourly data for today + tomorrow. If you add an API key, you can unlock longer horizons and finer resolution (depending on plan). The URL builder handles both.
  • Rate limiting: If you see HTTP 429, the script backs off and retries. Don’t schedule faster than the API updates (public: hourly).
  • Azimuth convention: Forecast.Solar uses 0° = south, 90° = west, 180° = north, 270° = east.


 

Be interesting to see if this is what you get !

 

 

 

 

InfluxDB 1.x?

 

 

If you’re on InfluxDB 1.x, install influxdb and swap the writer in write_points_influx() to use InfluxDBClient.write_points() with line protocol. I can paste a ready 1.x variant if you want it.

Posted
1 hour ago, Pocster said:

Be interesting to see if this is what you get !

Nope, yours is far, far worse. 222 lines 😂.

It gets the right endpoint at least which mine didn't, then fails completely when it comes to parsing the response.

  • Like 1
Posted
1 minute ago, S2D2 said:

Nope, yours is far, far worse. 222 lines 😂.

It gets the right endpoint at least which mine didn't, then fails completely when it comes to parsing the response.

Interesting that we get different versions!. I guess it's still learning!!

Posted
2 minutes ago, S2D2 said:

Nope, yours is far, far worse. 222 lines 😂.

It gets the right endpoint at least which mine didn't, then fails completely when it comes to parsing the response.

But does that code compile ok for you?. I go back to chat and tell it what's wrong - as you say it's parsing incorrectly. Then it takes 3 or 4 loops of try , fail, give feedback 

Posted
1 minute ago, Pocster said:

Interesting that we get different versions!. I guess it's still learning!!

 

No thats just the random number generator they added to make the models seem more human.

 

Apparently the earlier versions didn't have the RNG and you could get reproducible results but with other downsides.

Posted
10 minutes ago, -rick- said:

 

No thats just the random number generator they added to make the models seem more human.

 

Apparently the earlier versions didn't have the RNG and you could get reproducible results but with other downsides.

I have had it (expletive deleted) up . A comma missing , or the syntax is wrong etc . I just copy n paste the output back in . What I’ve developed would take a month on my own . I spend most time waiting for chat’s zip , downloading it , copying the file across and then rebuilding.That is a bit tedious . But then I get what I want without reading / internet surfing for days .

Posted

Exactly 👍 — you’ve got it.

 

When you and I generate code here → it’s just between us in this session (plus anything you’ve asked me to “remember” in your personal memory). I can’t go look up your code later unless you bring it back.

OpenAI improving models → sometimes a sample of chats (including code snippets) is taken offline, stripped of identifying details, and reviewed by humans or used in automated training. That’s where future models may learn patterns (e.g. “oh, lots of people wire ultrasonic sensors this way”).

Live ChatGPT (like now) → I don’t have access to some secret “vault of other people’s chats.” There’s no API or memory I can dip into for that.

 

 

So yes: in practice, code produced in conversations may be looked at offline and used to improve future model weights. But I can’t reach back and pull up that data — once this chat ends, I’m blind to it.

Posted

@S2D2 I went back to my mate chat . Bollocked it about your request and got this 

 

#!/usr/bin/env python3
import os, requests
from datetime import datetime, timezone
from influxdb_client import InfluxDBClient

# --- config via env ---
LAT  = os.environ["FS_LAT"];   LON = os.environ["FS_LON"]
DECL = os.environ["FS_DECL"];  AZI = os.environ["FS_AZIMUTH"]
KWP  = os.environ["FS_KWP"];   KEY = os.getenv("FS_API_KEY", "")
URL  = os.getenv("INFLUX_URL", "http://localhost:8086")
TOK  = os.environ["INFLUX_TOKEN"]; ORG = os.environ["INFLUX_ORG"]
BUC  = os.environ["INFLUX_BUCKET"]; MEAS = os.getenv("MEASUREMENT","solar_forecast")

# --- build forecast.solar URL (UTC timestamps) ---
base = "https://api.forecast.solar"
path = f"estimate/{float(LAT):.6f}/{float(LON):.6f}/{int(float(DECL))}/{int(float(AZI))}/{float(KWP):.3f}"
api  = f"{base}/{KEY}/{path}?time=utc" if KEY else f"{base}/{path}?time=utc"

# --- fetch & parse ---
js = requests.get(api, timeout=10).json()
watts = (js.get("result") or {}).get("watts") or {}
if not watts: raise SystemExit("No data from forecast.solar")

# --- write to InfluxDB 2.x ---
with InfluxDBClient(url=URL, token=TOK, org=ORG) as 😄
    w = c.write_api()
    # prepare minimal records: one point per hour with field 'watts'
    rec = []
    for ts, val in watts.items():
        dt = datetime.strptime(ts, "%Y-%m-%d %H:%M:%S").replace(tzinfo=timezone.utc)
        rec.append({"measurement": MEAS, "time": dt, "fields": {"watts": int(val)}})
    w.write(bucket=BUC, org=ORG, record=rec)

print(f"Wrote {len(watts)} hourly points to '{BUC}'")

Posted

Claims it can do better now !! 🤣

 

 

You could strip comments/env parsing and get it under ~25 lines.

 

 

But for clarity + correctness + efficiency, this is about as tight as it gets while still being maintainable.

 

👉 Want me to show you what a super-condensed version looks like (~20 lines, line protocol via requests.post), just to prove the point that it can be even leaner?

 

Really interested @S2D2 too see what you think of these attempts 

Posted
48 minutes ago, Pocster said:

Claims it can do better now !! 🤣

 

 

You could strip comments/env parsing and get it under ~25 lines.

 

 

But for clarity + correctness + efficiency, this is about as tight as it gets while still being maintainable.

 

👉 Want me to show you what a super-condensed version looks like (~20 lines, line protocol via requests.post), just to prove the point that it can be even leaner?

 

Really interested @S2D2 too see what you think of these attempts 

 

Personal highlight is how it's started cramming multiple env entries onto one line to get the line count down 😂.

 

It still fails to parse the response in the same way as before.

  • Haha 1

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...